1## @file
2# Generate AutoGen.h, AutoGen.c and *.depex files
3#
4# Copyright (c) 2007 - 2019, Intel Corporation. All rights reserved.<BR>
5# Copyright (c) 2018, Hewlett Packard Enterprise Development, L.P.<BR>
6# Copyright (c) 2019, American Megatrends, Inc. All rights reserved.<BR>
7#
8# SPDX-License-Identifier: BSD-2-Clause-Patent
9#
10
11## Import Modules
12#
13from __future__ import print_function
14from __future__ import absolute_import
15import Common.LongFilePathOs as os
16import re
17import os.path as path
18import copy
19import uuid
20
21from . import GenC
22from . import GenMake
23from . import GenDepex
24from io import BytesIO
25
26from .StrGather import *
27from .BuildEngine import BuildRule
28import shutil
29from Common.LongFilePathSupport import CopyLongFilePath
30from Common.BuildToolError import *
31from Common.DataType import *
32from Common.Misc import *
33from Common.StringUtils import *
34import Common.GlobalData as GlobalData
35from GenFds.FdfParser import *
36from CommonDataClass.CommonClass import SkuInfoClass
37from GenPatchPcdTable.GenPatchPcdTable import parsePcdInfoFromMapFile
38import Common.VpdInfoFile as VpdInfoFile
39from .GenPcdDb import CreatePcdDatabaseCode
40from Workspace.MetaFileCommentParser import UsageList
41from Workspace.WorkspaceCommon import GetModuleLibInstances
42from Common.MultipleWorkspace import MultipleWorkspace as mws
43from . import InfSectionParser
44import datetime
45import hashlib
46from .GenVar import VariableMgr, var_info
47from collections import OrderedDict
48from collections import defaultdict
49from Workspace.WorkspaceCommon import OrderedListDict
50from Common.ToolDefClassObject import gDefaultToolsDefFile
51
52from Common.caching import cached_property, cached_class_function
53
54## Regular expression for splitting Dependency Expression string into tokens
55gDepexTokenPattern = re.compile("(\(|\)|\w+| \S+\.inf)")
56
57## Regular expression for match: PCD(xxxx.yyy)
58gPCDAsGuidPattern = re.compile(r"^PCD\(.+\..+\)$")
59
60#
61# Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
62# is the former use /I , the Latter used -I to specify include directories
63#
64gBuildOptIncludePatternMsft = re.compile(r"(?:.*?)/I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)
65gBuildOptIncludePatternOther = re.compile(r"(?:.*?)-I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)
66
67#
68# Match name = variable
69#
70gEfiVarStoreNamePattern = re.compile("\s*name\s*=\s*(\w+)")
71#
72# The format of guid in efivarstore statement likes following and must be correct:
73# guid = {0xA04A27f4, 0xDF00, 0x4D42, {0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D}}
74#
75gEfiVarStoreGuidPattern = re.compile("\s*guid\s*=\s*({.*?{.*?}\s*})")
76
77## Mapping Makefile type
78gMakeTypeMap = {TAB_COMPILER_MSFT:"nmake", "GCC":"gmake"}
79
80
81## Build rule configuration file
82gDefaultBuildRuleFile = 'build_rule.txt'
83
84## Build rule default version
85AutoGenReqBuildRuleVerNum = "0.1"
86
87## default file name for AutoGen
88gAutoGenCodeFileName = "AutoGen.c"
89gAutoGenHeaderFileName = "AutoGen.h"
90gAutoGenStringFileName = "%(module_name)sStrDefs.h"
91gAutoGenStringFormFileName = "%(module_name)sStrDefs.hpk"
92gAutoGenDepexFileName = "%(module_name)s.depex"
93gAutoGenImageDefFileName = "%(module_name)sImgDefs.h"
94gAutoGenIdfFileName = "%(module_name)sIdf.hpk"
95gInfSpecVersion = "0x00010017"
96
97#
98# Template string to generic AsBuilt INF
99#
100gAsBuiltInfHeaderString = TemplateString("""${header_comments}
101
102# DO NOT EDIT
103# FILE auto-generated
104
105[Defines]
106  INF_VERSION                = ${module_inf_version}
107  BASE_NAME                  = ${module_name}
108  FILE_GUID                  = ${module_guid}
109  MODULE_TYPE                = ${module_module_type}${BEGIN}
110  VERSION_STRING             = ${module_version_string}${END}${BEGIN}
111  PCD_IS_DRIVER              = ${pcd_is_driver_string}${END}${BEGIN}
112  UEFI_SPECIFICATION_VERSION = ${module_uefi_specification_version}${END}${BEGIN}
113  PI_SPECIFICATION_VERSION   = ${module_pi_specification_version}${END}${BEGIN}
114  ENTRY_POINT                = ${module_entry_point}${END}${BEGIN}
115  UNLOAD_IMAGE               = ${module_unload_image}${END}${BEGIN}
116  CONSTRUCTOR                = ${module_constructor}${END}${BEGIN}
117  DESTRUCTOR                 = ${module_destructor}${END}${BEGIN}
118  SHADOW                     = ${module_shadow}${END}${BEGIN}
119  PCI_VENDOR_ID              = ${module_pci_vendor_id}${END}${BEGIN}
120  PCI_DEVICE_ID              = ${module_pci_device_id}${END}${BEGIN}
121  PCI_CLASS_CODE             = ${module_pci_class_code}${END}${BEGIN}
122  PCI_REVISION               = ${module_pci_revision}${END}${BEGIN}
123  BUILD_NUMBER               = ${module_build_number}${END}${BEGIN}
124  SPEC                       = ${module_spec}${END}${BEGIN}
125  UEFI_HII_RESOURCE_SECTION  = ${module_uefi_hii_resource_section}${END}${BEGIN}
126  MODULE_UNI_FILE            = ${module_uni_file}${END}
127
128[Packages.${module_arch}]${BEGIN}
129  ${package_item}${END}
130
131[Binaries.${module_arch}]${BEGIN}
132  ${binary_item}${END}
133
134[PatchPcd.${module_arch}]${BEGIN}
135  ${patchablepcd_item}
136${END}
137
138[Protocols.${module_arch}]${BEGIN}
139  ${protocol_item}
140${END}
141
142[Ppis.${module_arch}]${BEGIN}
143  ${ppi_item}
144${END}
145
146[Guids.${module_arch}]${BEGIN}
147  ${guid_item}
148${END}
149
150[PcdEx.${module_arch}]${BEGIN}
151  ${pcd_item}
152${END}
153
154[LibraryClasses.${module_arch}]
155## @LIB_INSTANCES${BEGIN}
156#  ${libraryclasses_item}${END}
157
158${depexsection_item}
159
160${userextension_tianocore_item}
161
162${tail_comments}
163
164[BuildOptions.${module_arch}]
165## @AsBuilt${BEGIN}
166##   ${flags_item}${END}
167""")
168## Split command line option string to list
169#
170# subprocess.Popen needs the args to be a sequence. Otherwise there's problem
171# in non-windows platform to launch command
172#
173def _SplitOption(OptionString):
174    OptionList = []
175    LastChar = " "
176    OptionStart = 0
177    QuotationMark = ""
178    for Index in range(0, len(OptionString)):
179        CurrentChar = OptionString[Index]
180        if CurrentChar in ['"', "'"]:
181            if QuotationMark == CurrentChar:
182                QuotationMark = ""
183            elif QuotationMark == "":
184                QuotationMark = CurrentChar
185            continue
186        elif QuotationMark:
187            continue
188
189        if CurrentChar in ["/", "-"] and LastChar in [" ", "\t", "\r", "\n"]:
190            if Index > OptionStart:
191                OptionList.append(OptionString[OptionStart:Index - 1])
192            OptionStart = Index
193        LastChar = CurrentChar
194    OptionList.append(OptionString[OptionStart:])
195    return OptionList
196
197#
198# Convert string to C format array
199#
200def _ConvertStringToByteArray(Value):
201    Value = Value.strip()
202    if not Value:
203        return None
204    if Value[0] == '{':
205        if not Value.endswith('}'):
206            return None
207        Value = Value.replace(' ', '').replace('{', '').replace('}', '')
208        ValFields = Value.split(',')
209        try:
210            for Index in range(len(ValFields)):
211                ValFields[Index] = str(int(ValFields[Index], 0))
212        except ValueError:
213            return None
214        Value = '{' + ','.join(ValFields) + '}'
215        return Value
216
217    Unicode = False
218    if Value.startswith('L"'):
219        if not Value.endswith('"'):
220            return None
221        Value = Value[1:]
222        Unicode = True
223    elif not Value.startswith('"') or not Value.endswith('"'):
224        return None
225
226    Value = eval(Value)         # translate escape character
227    NewValue = '{'
228    for Index in range(0, len(Value)):
229        if Unicode:
230            NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','
231        else:
232            NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','
233    Value = NewValue + '0}'
234    return Value
235
236## Base class for AutoGen
237#
238#   This class just implements the cache mechanism of AutoGen objects.
239#
240class AutoGen(object):
241    # database to maintain the objects in each child class
242    __ObjectCache = {}    # (BuildTarget, ToolChain, ARCH, platform file): AutoGen object
243
244    ## Factory method
245    #
246    #   @param  Class           class object of real AutoGen class
247    #                           (WorkspaceAutoGen, ModuleAutoGen or PlatformAutoGen)
248    #   @param  Workspace       Workspace directory or WorkspaceAutoGen object
249    #   @param  MetaFile        The path of meta file
250    #   @param  Target          Build target
251    #   @param  Toolchain       Tool chain name
252    #   @param  Arch            Target arch
253    #   @param  *args           The specific class related parameters
254    #   @param  **kwargs        The specific class related dict parameters
255    #
256    def __new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
257        # check if the object has been created
258        Key = (Target, Toolchain, Arch, MetaFile)
259        if Key in cls.__ObjectCache:
260            # if it exists, just return it directly
261            return cls.__ObjectCache[Key]
262            # it didnt exist. create it, cache it, then return it
263        RetVal = cls.__ObjectCache[Key] = super(AutoGen, cls).__new__(cls)
264        return RetVal
265
266
267    ## hash() operator
268    #
269    #  The file path of platform file will be used to represent hash value of this object
270    #
271    #   @retval int     Hash value of the file path of platform file
272    #
273    def __hash__(self):
274        return hash(self.MetaFile)
275
276    ## str() operator
277    #
278    #  The file path of platform file will be used to represent this object
279    #
280    #   @retval string  String of platform file path
281    #
282    def __str__(self):
283        return str(self.MetaFile)
284
285    ## "==" operator
286    def __eq__(self, Other):
287        return Other and self.MetaFile == Other
288
289## Workspace AutoGen class
290#
291#   This class is used mainly to control the whole platform build for different
292# architecture. This class will generate top level makefile.
293#
294class WorkspaceAutoGen(AutoGen):
295    # call super().__init__ then call the worker function with different parameter count
296    def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
297        if not hasattr(self, "_Init"):
298            self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
299            self._Init = True
300
301    ## Initialize WorkspaceAutoGen
302    #
303    #   @param  WorkspaceDir            Root directory of workspace
304    #   @param  ActivePlatform          Meta-file of active platform
305    #   @param  Target                  Build target
306    #   @param  Toolchain               Tool chain name
307    #   @param  ArchList                List of architecture of current build
308    #   @param  MetaFileDb              Database containing meta-files
309    #   @param  BuildConfig             Configuration of build
310    #   @param  ToolDefinition          Tool chain definitions
311    #   @param  FlashDefinitionFile     File of flash definition
312    #   @param  Fds                     FD list to be generated
313    #   @param  Fvs                     FV list to be generated
314    #   @param  Caps                    Capsule list to be generated
315    #   @param  SkuId                   SKU id from command line
316    #
317    def _InitWorker(self, WorkspaceDir, ActivePlatform, Target, Toolchain, ArchList, MetaFileDb,
318              BuildConfig, ToolDefinition, FlashDefinitionFile='', Fds=None, Fvs=None, Caps=None, SkuId='', UniFlag=None,
319              Progress=None, BuildModule=None):
320        self.BuildDatabase  = MetaFileDb
321        self.MetaFile       = ActivePlatform
322        self.WorkspaceDir   = WorkspaceDir
323        self.Platform       = self.BuildDatabase[self.MetaFile, TAB_ARCH_COMMON, Target, Toolchain]
324        GlobalData.gActivePlatform = self.Platform
325        self.BuildTarget    = Target
326        self.ToolChain      = Toolchain
327        self.ArchList       = ArchList
328        self.SkuId          = SkuId
329        self.UniFlag        = UniFlag
330
331        self.TargetTxt      = BuildConfig
332        self.ToolDef        = ToolDefinition
333        self.FdfFile        = FlashDefinitionFile
334        self.FdTargetList   = Fds if Fds else []
335        self.FvTargetList   = Fvs if Fvs else []
336        self.CapTargetList  = Caps if Caps else []
337        self.AutoGenObjectList = []
338        self._GuidDict = {}
339
340        # there's many relative directory operations, so ...
341        os.chdir(self.WorkspaceDir)
342
343        #
344        # Merge Arch
345        #
346        if not self.ArchList:
347            ArchList = set(self.Platform.SupArchList)
348        else:
349            ArchList = set(self.ArchList) & set(self.Platform.SupArchList)
350        if not ArchList:
351            EdkLogger.error("build", PARAMETER_INVALID,
352                            ExtraData = "Invalid ARCH specified. [Valid ARCH: %s]" % (" ".join(self.Platform.SupArchList)))
353        elif self.ArchList and len(ArchList) != len(self.ArchList):
354            SkippedArchList = set(self.ArchList).symmetric_difference(set(self.Platform.SupArchList))
355            EdkLogger.verbose("\nArch [%s] is ignored because the platform supports [%s] only!"
356                              % (" ".join(SkippedArchList), " ".join(self.Platform.SupArchList)))
357        self.ArchList = tuple(ArchList)
358
359        # Validate build target
360        if self.BuildTarget not in self.Platform.BuildTargets:
361            EdkLogger.error("build", PARAMETER_INVALID,
362                            ExtraData="Build target [%s] is not supported by the platform. [Valid target: %s]"
363                                      % (self.BuildTarget, " ".join(self.Platform.BuildTargets)))
364
365
366        # parse FDF file to get PCDs in it, if any
367        if not self.FdfFile:
368            self.FdfFile = self.Platform.FlashDefinition
369
370        EdkLogger.info("")
371        if self.ArchList:
372            EdkLogger.info('%-16s = %s' % ("Architecture(s)", ' '.join(self.ArchList)))
373        EdkLogger.info('%-16s = %s' % ("Build target", self.BuildTarget))
374        EdkLogger.info('%-16s = %s' % ("Toolchain", self.ToolChain))
375
376        EdkLogger.info('\n%-24s = %s' % ("Active Platform", self.Platform))
377        if BuildModule:
378            EdkLogger.info('%-24s = %s' % ("Active Module", BuildModule))
379
380        if self.FdfFile:
381            EdkLogger.info('%-24s = %s' % ("Flash Image Definition", self.FdfFile))
382
383        EdkLogger.verbose("\nFLASH_DEFINITION = %s" % self.FdfFile)
384
385        if Progress:
386            Progress.Start("\nProcessing meta-data")
387
388        if self.FdfFile:
389            #
390            # Mark now build in AutoGen Phase
391            #
392            GlobalData.gAutoGenPhase = True
393            Fdf = FdfParser(self.FdfFile.Path)
394            Fdf.ParseFile()
395            GlobalData.gFdfParser = Fdf
396            GlobalData.gAutoGenPhase = False
397            PcdSet = Fdf.Profile.PcdDict
398            if Fdf.CurrentFdName and Fdf.CurrentFdName in Fdf.Profile.FdDict:
399                FdDict = Fdf.Profile.FdDict[Fdf.CurrentFdName]
400                for FdRegion in FdDict.RegionList:
401                    if str(FdRegion.RegionType) is 'FILE' and self.Platform.VpdToolGuid in str(FdRegion.RegionDataList):
402                        if int(FdRegion.Offset) % 8 != 0:
403                            EdkLogger.error("build", FORMAT_INVALID, 'The VPD Base Address %s must be 8-byte aligned.' % (FdRegion.Offset))
404            ModuleList = Fdf.Profile.InfList
405            self.FdfProfile = Fdf.Profile
406            for fvname in self.FvTargetList:
407                if fvname.upper() not in self.FdfProfile.FvDict:
408                    EdkLogger.error("build", OPTION_VALUE_INVALID,
409                                    "No such an FV in FDF file: %s" % fvname)
410
411            # In DSC file may use FILE_GUID to override the module, then in the Platform.Modules use FILE_GUIDmodule.inf as key,
412            # but the path (self.MetaFile.Path) is the real path
413            for key in self.FdfProfile.InfDict:
414                if key == 'ArchTBD':
415                    MetaFile_cache = defaultdict(set)
416                    for Arch in self.ArchList:
417                        Current_Platform_cache = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
418                        for Pkey in Current_Platform_cache.Modules:
419                            MetaFile_cache[Arch].add(Current_Platform_cache.Modules[Pkey].MetaFile)
420                    for Inf in self.FdfProfile.InfDict[key]:
421                        ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
422                        for Arch in self.ArchList:
423                            if ModuleFile in MetaFile_cache[Arch]:
424                                break
425                        else:
426                            ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
427                            if not ModuleData.IsBinaryModule:
428                                EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
429
430                else:
431                    for Arch in self.ArchList:
432                        if Arch == key:
433                            Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
434                            MetaFileList = set()
435                            for Pkey in Platform.Modules:
436                                MetaFileList.add(Platform.Modules[Pkey].MetaFile)
437                            for Inf in self.FdfProfile.InfDict[key]:
438                                ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
439                                if ModuleFile in MetaFileList:
440                                    continue
441                                ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
442                                if not ModuleData.IsBinaryModule:
443                                    EdkLogger.error('build', PARSER_ERROR, "Module %s NOT found in DSC file; Is it really a binary module?" % ModuleFile)
444
445        else:
446            PcdSet = {}
447            ModuleList = []
448            self.FdfProfile = None
449            if self.FdTargetList:
450                EdkLogger.info("No flash definition file found. FD [%s] will be ignored." % " ".join(self.FdTargetList))
451                self.FdTargetList = []
452            if self.FvTargetList:
453                EdkLogger.info("No flash definition file found. FV [%s] will be ignored." % " ".join(self.FvTargetList))
454                self.FvTargetList = []
455            if self.CapTargetList:
456                EdkLogger.info("No flash definition file found. Capsule [%s] will be ignored." % " ".join(self.CapTargetList))
457                self.CapTargetList = []
458
459        # apply SKU and inject PCDs from Flash Definition file
460        for Arch in self.ArchList:
461            Platform = self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]
462            PlatformPcds = Platform.Pcds
463            self._GuidDict = Platform._GuidDict
464            SourcePcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set(),TAB_PCDS_DYNAMIC:set(),TAB_PCDS_FIXED_AT_BUILD:set()}
465            BinaryPcdDict = {TAB_PCDS_DYNAMIC_EX:set(), TAB_PCDS_PATCHABLE_IN_MODULE:set()}
466            SourcePcdDict_Keys = SourcePcdDict.keys()
467            BinaryPcdDict_Keys = BinaryPcdDict.keys()
468
469            # generate the SourcePcdDict and BinaryPcdDict
470            PGen = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)
471            for BuildData in list(PGen.BuildDatabase._CACHE_.values()):
472                if BuildData.Arch != Arch:
473                    continue
474                if BuildData.MetaFile.Ext == '.inf':
475                    for key in BuildData.Pcds:
476                        if BuildData.Pcds[key].Pending:
477                            if key in Platform.Pcds:
478                                PcdInPlatform = Platform.Pcds[key]
479                                if PcdInPlatform.Type:
480                                    BuildData.Pcds[key].Type = PcdInPlatform.Type
481                                    BuildData.Pcds[key].Pending = False
482
483                            if BuildData.MetaFile in Platform.Modules:
484                                PlatformModule = Platform.Modules[str(BuildData.MetaFile)]
485                                if key in PlatformModule.Pcds:
486                                    PcdInPlatform = PlatformModule.Pcds[key]
487                                    if PcdInPlatform.Type:
488                                        BuildData.Pcds[key].Type = PcdInPlatform.Type
489                                        BuildData.Pcds[key].Pending = False
490                            else:
491                                #Pcd used in Library, Pcd Type from reference module if Pcd Type is Pending
492                                if BuildData.Pcds[key].Pending:
493                                    MGen = ModuleAutoGen(self, BuildData.MetaFile, Target, Toolchain, Arch, self.MetaFile)
494                                    if MGen and MGen.IsLibrary:
495                                        if MGen in PGen.LibraryAutoGenList:
496                                            ReferenceModules = MGen.ReferenceModules
497                                            for ReferenceModule in ReferenceModules:
498                                                if ReferenceModule.MetaFile in Platform.Modules:
499                                                    RefPlatformModule = Platform.Modules[str(ReferenceModule.MetaFile)]
500                                                    if key in RefPlatformModule.Pcds:
501                                                        PcdInReferenceModule = RefPlatformModule.Pcds[key]
502                                                        if PcdInReferenceModule.Type:
503                                                            BuildData.Pcds[key].Type = PcdInReferenceModule.Type
504                                                            BuildData.Pcds[key].Pending = False
505                                                            break
506
507                        if TAB_PCDS_DYNAMIC_EX in BuildData.Pcds[key].Type:
508                            if BuildData.IsBinaryModule:
509                                BinaryPcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
510                            else:
511                                SourcePcdDict[TAB_PCDS_DYNAMIC_EX].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
512
513                        elif TAB_PCDS_PATCHABLE_IN_MODULE in BuildData.Pcds[key].Type:
514                            if BuildData.MetaFile.Ext == '.inf':
515                                if BuildData.IsBinaryModule:
516                                    BinaryPcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
517                                else:
518                                    SourcePcdDict[TAB_PCDS_PATCHABLE_IN_MODULE].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
519
520                        elif TAB_PCDS_DYNAMIC in BuildData.Pcds[key].Type:
521                            SourcePcdDict[TAB_PCDS_DYNAMIC].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
522                        elif TAB_PCDS_FIXED_AT_BUILD in BuildData.Pcds[key].Type:
523                            SourcePcdDict[TAB_PCDS_FIXED_AT_BUILD].add((BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName))
524                else:
525                    pass
526            #
527            # A PCD can only use one type for all source modules
528            #
529            for i in SourcePcdDict_Keys:
530                for j in SourcePcdDict_Keys:
531                    if i != j:
532                        Intersections = SourcePcdDict[i].intersection(SourcePcdDict[j])
533                        if len(Intersections) > 0:
534                            EdkLogger.error(
535                            'build',
536                            FORMAT_INVALID,
537                            "Building modules from source INFs, following PCD use %s and %s access method. It must be corrected to use only one access method." % (i, j),
538                            ExtraData='\n\t'.join(str(P[1]+'.'+P[0]) for P in Intersections)
539                            )
540
541            #
542            # intersection the BinaryPCD for Mixed PCD
543            #
544            for i in BinaryPcdDict_Keys:
545                for j in BinaryPcdDict_Keys:
546                    if i != j:
547                        Intersections = BinaryPcdDict[i].intersection(BinaryPcdDict[j])
548                        for item in Intersections:
549                            NewPcd1 = (item[0] + '_' + i, item[1])
550                            NewPcd2 = (item[0] + '_' + j, item[1])
551                            if item not in GlobalData.MixedPcd:
552                                GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
553                            else:
554                                if NewPcd1 not in GlobalData.MixedPcd[item]:
555                                    GlobalData.MixedPcd[item].append(NewPcd1)
556                                if NewPcd2 not in GlobalData.MixedPcd[item]:
557                                    GlobalData.MixedPcd[item].append(NewPcd2)
558
559            #
560            # intersection the SourcePCD and BinaryPCD for Mixed PCD
561            #
562            for i in SourcePcdDict_Keys:
563                for j in BinaryPcdDict_Keys:
564                    if i != j:
565                        Intersections = SourcePcdDict[i].intersection(BinaryPcdDict[j])
566                        for item in Intersections:
567                            NewPcd1 = (item[0] + '_' + i, item[1])
568                            NewPcd2 = (item[0] + '_' + j, item[1])
569                            if item not in GlobalData.MixedPcd:
570                                GlobalData.MixedPcd[item] = [NewPcd1, NewPcd2]
571                            else:
572                                if NewPcd1 not in GlobalData.MixedPcd[item]:
573                                    GlobalData.MixedPcd[item].append(NewPcd1)
574                                if NewPcd2 not in GlobalData.MixedPcd[item]:
575                                    GlobalData.MixedPcd[item].append(NewPcd2)
576
577            for BuildData in list(PGen.BuildDatabase._CACHE_.values()):
578                if BuildData.Arch != Arch:
579                    continue
580                for key in BuildData.Pcds:
581                    for SinglePcd in GlobalData.MixedPcd:
582                        if (BuildData.Pcds[key].TokenCName, BuildData.Pcds[key].TokenSpaceGuidCName) == SinglePcd:
583                            for item in GlobalData.MixedPcd[SinglePcd]:
584                                Pcd_Type = item[0].split('_')[-1]
585                                if (Pcd_Type == BuildData.Pcds[key].Type) or (Pcd_Type == TAB_PCDS_DYNAMIC_EX and BuildData.Pcds[key].Type in PCD_DYNAMIC_EX_TYPE_SET) or \
586                                   (Pcd_Type == TAB_PCDS_DYNAMIC and BuildData.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET):
587                                    Value = BuildData.Pcds[key]
588                                    Value.TokenCName = BuildData.Pcds[key].TokenCName + '_' + Pcd_Type
589                                    if len(key) == 2:
590                                        newkey = (Value.TokenCName, key[1])
591                                    elif len(key) == 3:
592                                        newkey = (Value.TokenCName, key[1], key[2])
593                                    del BuildData.Pcds[key]
594                                    BuildData.Pcds[newkey] = Value
595                                    break
596                            break
597
598            # handle the mixed pcd in FDF file
599            for key in PcdSet:
600                if key in GlobalData.MixedPcd:
601                    Value = PcdSet[key]
602                    del PcdSet[key]
603                    for item in GlobalData.MixedPcd[key]:
604                        PcdSet[item] = Value
605
606            #Collect package set information from INF of FDF
607            PkgSet = set()
608            for Inf in ModuleList:
609                ModuleFile = PathClass(NormPath(Inf), GlobalData.gWorkspace, Arch)
610                if ModuleFile in Platform.Modules:
611                    continue
612                ModuleData = self.BuildDatabase[ModuleFile, Arch, Target, Toolchain]
613                PkgSet.update(ModuleData.Packages)
614            Pkgs = list(PkgSet) + list(PGen.PackageList)
615            DecPcds = set()
616            DecPcdsKey = set()
617            for Pkg in Pkgs:
618                for Pcd in Pkg.Pcds:
619                    DecPcds.add((Pcd[0], Pcd[1]))
620                    DecPcdsKey.add((Pcd[0], Pcd[1], Pcd[2]))
621
622            Platform.SkuName = self.SkuId
623            for Name, Guid,Fileds in PcdSet:
624                if (Name, Guid) not in DecPcds:
625                    EdkLogger.error(
626                        'build',
627                        PARSER_ERROR,
628                        "PCD (%s.%s) used in FDF is not declared in DEC files." % (Guid, Name),
629                        File = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][0],
630                        Line = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][1]
631                    )
632                else:
633                    # Check whether Dynamic or DynamicEx PCD used in FDF file. If used, build break and give a error message.
634                    if (Name, Guid, TAB_PCDS_FIXED_AT_BUILD) in DecPcdsKey \
635                        or (Name, Guid, TAB_PCDS_PATCHABLE_IN_MODULE) in DecPcdsKey \
636                        or (Name, Guid, TAB_PCDS_FEATURE_FLAG) in DecPcdsKey:
637                        continue
638                    elif (Name, Guid, TAB_PCDS_DYNAMIC) in DecPcdsKey or (Name, Guid, TAB_PCDS_DYNAMIC_EX) in DecPcdsKey:
639                        EdkLogger.error(
640                                'build',
641                                PARSER_ERROR,
642                                "Using Dynamic or DynamicEx type of PCD [%s.%s] in FDF file is not allowed." % (Guid, Name),
643                                File = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][0],
644                                Line = self.FdfProfile.PcdFileLineDict[Name, Guid, Fileds][1]
645                        )
646
647            Pa = PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch)
648            #
649            # Explicitly collect platform's dynamic PCDs
650            #
651            Pa.CollectPlatformDynamicPcds()
652            Pa.CollectFixedAtBuildPcds()
653            self.AutoGenObjectList.append(Pa)
654
655            #
656            # Generate Package level hash value
657            #
658            GlobalData.gPackageHash = {}
659            if GlobalData.gUseHashCache:
660                for Pkg in Pkgs:
661                    self._GenPkgLevelHash(Pkg)
662
663        #
664        # Check PCDs token value conflict in each DEC file.
665        #
666        self._CheckAllPcdsTokenValueConflict()
667
668        #
669        # Check PCD type and definition between DSC and DEC
670        #
671        self._CheckPcdDefineAndType()
672
673        #
674        # Create BuildOptions Macro & PCD metafile, also add the Active Platform and FDF file.
675        #
676        content = 'gCommandLineDefines: '
677        content += str(GlobalData.gCommandLineDefines)
678        content += TAB_LINE_BREAK
679        content += 'BuildOptionPcd: '
680        content += str(GlobalData.BuildOptionPcd)
681        content += TAB_LINE_BREAK
682        content += 'Active Platform: '
683        content += str(self.Platform)
684        content += TAB_LINE_BREAK
685        if self.FdfFile:
686            content += 'Flash Image Definition: '
687            content += str(self.FdfFile)
688            content += TAB_LINE_BREAK
689        SaveFileOnChange(os.path.join(self.BuildDir, 'BuildOptions'), content, False)
690
691        #
692        # Create PcdToken Number file for Dynamic/DynamicEx Pcd.
693        #
694        PcdTokenNumber = 'PcdTokenNumber: '
695        if Pa.PcdTokenNumber:
696            if Pa.DynamicPcdList:
697                for Pcd in Pa.DynamicPcdList:
698                    PcdTokenNumber += TAB_LINE_BREAK
699                    PcdTokenNumber += str((Pcd.TokenCName, Pcd.TokenSpaceGuidCName))
700                    PcdTokenNumber += ' : '
701                    PcdTokenNumber += str(Pa.PcdTokenNumber[Pcd.TokenCName, Pcd.TokenSpaceGuidCName])
702        SaveFileOnChange(os.path.join(self.BuildDir, 'PcdTokenNumber'), PcdTokenNumber, False)
703
704        #
705        # Get set of workspace metafiles
706        #
707        AllWorkSpaceMetaFiles = self._GetMetaFiles(Target, Toolchain, Arch)
708
709        #
710        # Retrieve latest modified time of all metafiles
711        #
712        SrcTimeStamp = 0
713        for f in AllWorkSpaceMetaFiles:
714            if os.stat(f)[8] > SrcTimeStamp:
715                SrcTimeStamp = os.stat(f)[8]
716        self._SrcTimeStamp = SrcTimeStamp
717
718        if GlobalData.gUseHashCache:
719            m = hashlib.md5()
720            for files in AllWorkSpaceMetaFiles:
721                if files.endswith('.dec'):
722                    continue
723                f = open(files, 'rb')
724                Content = f.read()
725                f.close()
726                m.update(Content)
727            SaveFileOnChange(os.path.join(self.BuildDir, 'AutoGen.hash'), m.hexdigest(), False)
728            GlobalData.gPlatformHash = m.hexdigest()
729
730        #
731        # Write metafile list to build directory
732        #
733        AutoGenFilePath = os.path.join(self.BuildDir, 'AutoGen')
734        if os.path.exists (AutoGenFilePath):
735            os.remove(AutoGenFilePath)
736        if not os.path.exists(self.BuildDir):
737            os.makedirs(self.BuildDir)
738        with open(os.path.join(self.BuildDir, 'AutoGen'), 'w+') as file:
739            for f in AllWorkSpaceMetaFiles:
740                print(f, file=file)
741        return True
742
743    def _GenPkgLevelHash(self, Pkg):
744        if Pkg.PackageName in GlobalData.gPackageHash:
745            return
746
747        PkgDir = os.path.join(self.BuildDir, Pkg.Arch, Pkg.PackageName)
748        CreateDirectory(PkgDir)
749        HashFile = os.path.join(PkgDir, Pkg.PackageName + '.hash')
750        m = hashlib.md5()
751        # Get .dec file's hash value
752        f = open(Pkg.MetaFile.Path, 'rb')
753        Content = f.read()
754        f.close()
755        m.update(Content)
756        # Get include files hash value
757        if Pkg.Includes:
758            for inc in sorted(Pkg.Includes, key=lambda x: str(x)):
759                for Root, Dirs, Files in os.walk(str(inc)):
760                    for File in sorted(Files):
761                        File_Path = os.path.join(Root, File)
762                        f = open(File_Path, 'rb')
763                        Content = f.read()
764                        f.close()
765                        m.update(Content)
766        SaveFileOnChange(HashFile, m.hexdigest(), False)
767        GlobalData.gPackageHash[Pkg.PackageName] = m.hexdigest()
768
769    def _GetMetaFiles(self, Target, Toolchain, Arch):
770        AllWorkSpaceMetaFiles = set()
771        #
772        # add fdf
773        #
774        if self.FdfFile:
775            AllWorkSpaceMetaFiles.add (self.FdfFile.Path)
776            for f in GlobalData.gFdfParser.GetAllIncludedFile():
777                AllWorkSpaceMetaFiles.add (f.FileName)
778        #
779        # add dsc
780        #
781        AllWorkSpaceMetaFiles.add(self.MetaFile.Path)
782
783        #
784        # add build_rule.txt & tools_def.txt
785        #
786        AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultBuildRuleFile))
787        AllWorkSpaceMetaFiles.add(os.path.join(GlobalData.gConfDirectory, gDefaultToolsDefFile))
788
789        # add BuildOption metafile
790        #
791        AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'BuildOptions'))
792
793        # add PcdToken Number file for Dynamic/DynamicEx Pcd
794        #
795        AllWorkSpaceMetaFiles.add(os.path.join(self.BuildDir, 'PcdTokenNumber'))
796
797        for Arch in self.ArchList:
798            #
799            # add dec
800            #
801            for Package in PlatformAutoGen(self, self.MetaFile, Target, Toolchain, Arch).PackageList:
802                AllWorkSpaceMetaFiles.add(Package.MetaFile.Path)
803
804            #
805            # add included dsc
806            #
807            for filePath in self.BuildDatabase[self.MetaFile, Arch, Target, Toolchain]._RawData.IncludedFiles:
808                AllWorkSpaceMetaFiles.add(filePath.Path)
809
810        return AllWorkSpaceMetaFiles
811
812    def _CheckPcdDefineAndType(self):
813        PcdTypeSet = {TAB_PCDS_FIXED_AT_BUILD,
814            TAB_PCDS_PATCHABLE_IN_MODULE,
815            TAB_PCDS_FEATURE_FLAG,
816            TAB_PCDS_DYNAMIC,
817            TAB_PCDS_DYNAMIC_EX}
818
819        # This dict store PCDs which are not used by any modules with specified arches
820        UnusedPcd = OrderedDict()
821        for Pa in self.AutoGenObjectList:
822            # Key of DSC's Pcds dictionary is PcdCName, TokenSpaceGuid
823            for Pcd in Pa.Platform.Pcds:
824                PcdType = Pa.Platform.Pcds[Pcd].Type
825
826                # If no PCD type, this PCD comes from FDF
827                if not PcdType:
828                    continue
829
830                # Try to remove Hii and Vpd suffix
831                if PcdType.startswith(TAB_PCDS_DYNAMIC_EX):
832                    PcdType = TAB_PCDS_DYNAMIC_EX
833                elif PcdType.startswith(TAB_PCDS_DYNAMIC):
834                    PcdType = TAB_PCDS_DYNAMIC
835
836                for Package in Pa.PackageList:
837                    # Key of DEC's Pcds dictionary is PcdCName, TokenSpaceGuid, PcdType
838                    if (Pcd[0], Pcd[1], PcdType) in Package.Pcds:
839                        break
840                    for Type in PcdTypeSet:
841                        if (Pcd[0], Pcd[1], Type) in Package.Pcds:
842                            EdkLogger.error(
843                                'build',
844                                FORMAT_INVALID,
845                                "Type [%s] of PCD [%s.%s] in DSC file doesn't match the type [%s] defined in DEC file." \
846                                % (Pa.Platform.Pcds[Pcd].Type, Pcd[1], Pcd[0], Type),
847                                ExtraData=None
848                            )
849                            return
850                else:
851                    UnusedPcd.setdefault(Pcd, []).append(Pa.Arch)
852
853        for Pcd in UnusedPcd:
854            EdkLogger.warn(
855                'build',
856                "The PCD was not specified by any INF module in the platform for the given architecture.\n"
857                "\tPCD: [%s.%s]\n\tPlatform: [%s]\n\tArch: %s"
858                % (Pcd[1], Pcd[0], os.path.basename(str(self.MetaFile)), str(UnusedPcd[Pcd])),
859                ExtraData=None
860            )
861
862    def __repr__(self):
863        return "%s [%s]" % (self.MetaFile, ", ".join(self.ArchList))
864
865    ## Return the directory to store FV files
866    @cached_property
867    def FvDir(self):
868        return path.join(self.BuildDir, TAB_FV_DIRECTORY)
869
870    ## Return the directory to store all intermediate and final files built
871    @cached_property
872    def BuildDir(self):
873        return self.AutoGenObjectList[0].BuildDir
874
875    ## Return the build output directory platform specifies
876    @cached_property
877    def OutputDir(self):
878        return self.Platform.OutputDirectory
879
880    ## Return platform name
881    @cached_property
882    def Name(self):
883        return self.Platform.PlatformName
884
885    ## Return meta-file GUID
886    @cached_property
887    def Guid(self):
888        return self.Platform.Guid
889
890    ## Return platform version
891    @cached_property
892    def Version(self):
893        return self.Platform.Version
894
895    ## Return paths of tools
896    @cached_property
897    def ToolDefinition(self):
898        return self.AutoGenObjectList[0].ToolDefinition
899
900    ## Return directory of platform makefile
901    #
902    #   @retval     string  Makefile directory
903    #
904    @cached_property
905    def MakeFileDir(self):
906        return self.BuildDir
907
908    ## Return build command string
909    #
910    #   @retval     string  Build command string
911    #
912    @cached_property
913    def BuildCommand(self):
914        # BuildCommand should be all the same. So just get one from platform AutoGen
915        return self.AutoGenObjectList[0].BuildCommand
916
917    ## Check the PCDs token value conflict in each DEC file.
918    #
919    # Will cause build break and raise error message while two PCDs conflict.
920    #
921    # @return  None
922    #
923    def _CheckAllPcdsTokenValueConflict(self):
924        for Pa in self.AutoGenObjectList:
925            for Package in Pa.PackageList:
926                PcdList = list(Package.Pcds.values())
927                PcdList.sort(key=lambda x: int(x.TokenValue, 0))
928                Count = 0
929                while (Count < len(PcdList) - 1) :
930                    Item = PcdList[Count]
931                    ItemNext = PcdList[Count + 1]
932                    #
933                    # Make sure in the same token space the TokenValue should be unique
934                    #
935                    if (int(Item.TokenValue, 0) == int(ItemNext.TokenValue, 0)):
936                        SameTokenValuePcdList = []
937                        SameTokenValuePcdList.append(Item)
938                        SameTokenValuePcdList.append(ItemNext)
939                        RemainPcdListLength = len(PcdList) - Count - 2
940                        for ValueSameCount in range(RemainPcdListLength):
941                            if int(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount].TokenValue, 0) == int(Item.TokenValue, 0):
942                                SameTokenValuePcdList.append(PcdList[len(PcdList) - RemainPcdListLength + ValueSameCount])
943                            else:
944                                break;
945                        #
946                        # Sort same token value PCD list with TokenGuid and TokenCName
947                        #
948                        SameTokenValuePcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
949                        SameTokenValuePcdListCount = 0
950                        while (SameTokenValuePcdListCount < len(SameTokenValuePcdList) - 1):
951                            Flag = False
952                            TemListItem = SameTokenValuePcdList[SameTokenValuePcdListCount]
953                            TemListItemNext = SameTokenValuePcdList[SameTokenValuePcdListCount + 1]
954
955                            if (TemListItem.TokenSpaceGuidCName == TemListItemNext.TokenSpaceGuidCName) and (TemListItem.TokenCName != TemListItemNext.TokenCName):
956                                for PcdItem in GlobalData.MixedPcd:
957                                    if (TemListItem.TokenCName, TemListItem.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem] or \
958                                        (TemListItemNext.TokenCName, TemListItemNext.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
959                                        Flag = True
960                                if not Flag:
961                                    EdkLogger.error(
962                                                'build',
963                                                FORMAT_INVALID,
964                                                "The TokenValue [%s] of PCD [%s.%s] is conflict with: [%s.%s] in %s"\
965                                                % (TemListItem.TokenValue, TemListItem.TokenSpaceGuidCName, TemListItem.TokenCName, TemListItemNext.TokenSpaceGuidCName, TemListItemNext.TokenCName, Package),
966                                                ExtraData=None
967                                                )
968                            SameTokenValuePcdListCount += 1
969                        Count += SameTokenValuePcdListCount
970                    Count += 1
971
972                PcdList = list(Package.Pcds.values())
973                PcdList.sort(key=lambda x: "%s.%s" % (x.TokenSpaceGuidCName, x.TokenCName))
974                Count = 0
975                while (Count < len(PcdList) - 1) :
976                    Item = PcdList[Count]
977                    ItemNext = PcdList[Count + 1]
978                    #
979                    # Check PCDs with same TokenSpaceGuidCName.TokenCName have same token value as well.
980                    #
981                    if (Item.TokenSpaceGuidCName == ItemNext.TokenSpaceGuidCName) and (Item.TokenCName == ItemNext.TokenCName) and (int(Item.TokenValue, 0) != int(ItemNext.TokenValue, 0)):
982                        EdkLogger.error(
983                                    'build',
984                                    FORMAT_INVALID,
985                                    "The TokenValue [%s] of PCD [%s.%s] in %s defined in two places should be same as well."\
986                                    % (Item.TokenValue, Item.TokenSpaceGuidCName, Item.TokenCName, Package),
987                                    ExtraData=None
988                                    )
989                    Count += 1
990    ## Generate fds command
991    @property
992    def GenFdsCommand(self):
993        return (GenMake.TopLevelMakefile(self)._TEMPLATE_.Replace(GenMake.TopLevelMakefile(self)._TemplateDict)).strip()
994
995    @property
996    def GenFdsCommandDict(self):
997        FdsCommandDict = {}
998        LogLevel = EdkLogger.GetLevel()
999        if LogLevel == EdkLogger.VERBOSE:
1000            FdsCommandDict["verbose"] = True
1001        elif LogLevel <= EdkLogger.DEBUG_9:
1002            FdsCommandDict["debug"] = LogLevel - 1
1003        elif LogLevel == EdkLogger.QUIET:
1004            FdsCommandDict["quiet"] = True
1005
1006        if GlobalData.gEnableGenfdsMultiThread:
1007            FdsCommandDict["GenfdsMultiThread"] = True
1008        if GlobalData.gIgnoreSource:
1009            FdsCommandDict["IgnoreSources"] = True
1010
1011        FdsCommandDict["OptionPcd"] = []
1012        for pcd in GlobalData.BuildOptionPcd:
1013            if pcd[2]:
1014                pcdname = '.'.join(pcd[0:3])
1015            else:
1016                pcdname = '.'.join(pcd[0:2])
1017            if pcd[3].startswith('{'):
1018                FdsCommandDict["OptionPcd"].append(pcdname + '=' + 'H' + '"' + pcd[3] + '"')
1019            else:
1020                FdsCommandDict["OptionPcd"].append(pcdname + '=' + pcd[3])
1021
1022        MacroList = []
1023        # macros passed to GenFds
1024        MacroDict = {}
1025        MacroDict.update(GlobalData.gGlobalDefines)
1026        MacroDict.update(GlobalData.gCommandLineDefines)
1027        for MacroName in MacroDict:
1028            if MacroDict[MacroName] != "":
1029                MacroList.append('"%s=%s"' % (MacroName, MacroDict[MacroName].replace('\\', '\\\\')))
1030            else:
1031                MacroList.append('"%s"' % MacroName)
1032        FdsCommandDict["macro"] = MacroList
1033
1034        FdsCommandDict["fdf_file"] = [self.FdfFile]
1035        FdsCommandDict["build_target"] = self.BuildTarget
1036        FdsCommandDict["toolchain_tag"] = self.ToolChain
1037        FdsCommandDict["active_platform"] = str(self)
1038
1039        FdsCommandDict["conf_directory"] = GlobalData.gConfDirectory
1040        FdsCommandDict["build_architecture_list"] = ','.join(self.ArchList)
1041        FdsCommandDict["platform_build_directory"] = self.BuildDir
1042
1043        FdsCommandDict["fd"] = self.FdTargetList
1044        FdsCommandDict["fv"] = self.FvTargetList
1045        FdsCommandDict["cap"] = self.CapTargetList
1046        return FdsCommandDict
1047
1048    ## Create makefile for the platform and modules in it
1049    #
1050    #   @param      CreateDepsMakeFile      Flag indicating if the makefile for
1051    #                                       modules will be created as well
1052    #
1053    def CreateMakeFile(self, CreateDepsMakeFile=False):
1054        if not CreateDepsMakeFile:
1055            return
1056        for Pa in self.AutoGenObjectList:
1057            Pa.CreateMakeFile(True)
1058
1059    ## Create autogen code for platform and modules
1060    #
1061    #  Since there's no autogen code for platform, this method will do nothing
1062    #  if CreateModuleCodeFile is set to False.
1063    #
1064    #   @param      CreateDepsCodeFile      Flag indicating if creating module's
1065    #                                       autogen code file or not
1066    #
1067    def CreateCodeFile(self, CreateDepsCodeFile=False):
1068        if not CreateDepsCodeFile:
1069            return
1070        for Pa in self.AutoGenObjectList:
1071            Pa.CreateCodeFile(True)
1072
1073    ## Create AsBuilt INF file the platform
1074    #
1075    def CreateAsBuiltInf(self):
1076        return
1077
1078
1079## AutoGen class for platform
1080#
1081#  PlatformAutoGen class will process the original information in platform
1082#  file in order to generate makefile for platform.
1083#
1084class PlatformAutoGen(AutoGen):
1085    # call super().__init__ then call the worker function with different parameter count
1086    def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
1087        if not hasattr(self, "_Init"):
1088            self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch)
1089            self._Init = True
1090    #
1091    # Used to store all PCDs for both PEI and DXE phase, in order to generate
1092    # correct PCD database
1093    #
1094    _DynaPcdList_ = []
1095    _NonDynaPcdList_ = []
1096    _PlatformPcds = {}
1097
1098    #
1099    # The priority list while override build option
1100    #
1101    PrioList = {"0x11111"  : 16,     #  TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE (Highest)
1102                "0x01111"  : 15,     #  ******_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
1103                "0x10111"  : 14,     #  TARGET_*********_ARCH_COMMANDTYPE_ATTRIBUTE
1104                "0x00111"  : 13,     #  ******_*********_ARCH_COMMANDTYPE_ATTRIBUTE
1105                "0x11011"  : 12,     #  TARGET_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE
1106                "0x01011"  : 11,     #  ******_TOOLCHAIN_****_COMMANDTYPE_ATTRIBUTE
1107                "0x10011"  : 10,     #  TARGET_*********_****_COMMANDTYPE_ATTRIBUTE
1108                "0x00011"  : 9,      #  ******_*********_****_COMMANDTYPE_ATTRIBUTE
1109                "0x11101"  : 8,      #  TARGET_TOOLCHAIN_ARCH_***********_ATTRIBUTE
1110                "0x01101"  : 7,      #  ******_TOOLCHAIN_ARCH_***********_ATTRIBUTE
1111                "0x10101"  : 6,      #  TARGET_*********_ARCH_***********_ATTRIBUTE
1112                "0x00101"  : 5,      #  ******_*********_ARCH_***********_ATTRIBUTE
1113                "0x11001"  : 4,      #  TARGET_TOOLCHAIN_****_***********_ATTRIBUTE
1114                "0x01001"  : 3,      #  ******_TOOLCHAIN_****_***********_ATTRIBUTE
1115                "0x10001"  : 2,      #  TARGET_*********_****_***********_ATTRIBUTE
1116                "0x00001"  : 1}      #  ******_*********_****_***********_ATTRIBUTE (Lowest)
1117
1118    ## Initialize PlatformAutoGen
1119    #
1120    #
1121    #   @param      Workspace       WorkspaceAutoGen object
1122    #   @param      PlatformFile    Platform file (DSC file)
1123    #   @param      Target          Build target (DEBUG, RELEASE)
1124    #   @param      Toolchain       Name of tool chain
1125    #   @param      Arch            arch of the platform supports
1126    #
1127    def _InitWorker(self, Workspace, PlatformFile, Target, Toolchain, Arch):
1128        EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen platform [%s] [%s]" % (PlatformFile, Arch))
1129        GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (PlatformFile, Arch, Toolchain, Target)
1130
1131        self.MetaFile = PlatformFile
1132        self.Workspace = Workspace
1133        self.WorkspaceDir = Workspace.WorkspaceDir
1134        self.ToolChain = Toolchain
1135        self.BuildTarget = Target
1136        self.Arch = Arch
1137        self.SourceDir = PlatformFile.SubDir
1138        self.FdTargetList = self.Workspace.FdTargetList
1139        self.FvTargetList = self.Workspace.FvTargetList
1140        # get the original module/package/platform objects
1141        self.BuildDatabase = Workspace.BuildDatabase
1142        self.DscBuildDataObj = Workspace.Platform
1143
1144        # flag indicating if the makefile/C-code file has been created or not
1145        self.IsMakeFileCreated  = False
1146
1147        self._DynamicPcdList = None    # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
1148        self._NonDynamicPcdList = None # [(TokenCName1, TokenSpaceGuidCName1), (TokenCName2, TokenSpaceGuidCName2), ...]
1149
1150        self._AsBuildInfList = []
1151        self._AsBuildModuleList = []
1152
1153        self.VariableInfo = None
1154
1155        if GlobalData.gFdfParser is not None:
1156            self._AsBuildInfList = GlobalData.gFdfParser.Profile.InfList
1157            for Inf in self._AsBuildInfList:
1158                InfClass = PathClass(NormPath(Inf), GlobalData.gWorkspace, self.Arch)
1159                M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
1160                if not M.IsBinaryModule:
1161                    continue
1162                self._AsBuildModuleList.append(InfClass)
1163        # get library/modules for build
1164        self.LibraryBuildDirectoryList = []
1165        self.ModuleBuildDirectoryList = []
1166
1167        return True
1168
1169    @cached_class_function
1170    def __repr__(self):
1171        return "%s [%s]" % (self.MetaFile, self.Arch)
1172
1173    ## Create autogen code for platform and modules
1174    #
1175    #  Since there's no autogen code for platform, this method will do nothing
1176    #  if CreateModuleCodeFile is set to False.
1177    #
1178    #   @param      CreateModuleCodeFile    Flag indicating if creating module's
1179    #                                       autogen code file or not
1180    #
1181    @cached_class_function
1182    def CreateCodeFile(self, CreateModuleCodeFile=False):
1183        # only module has code to be created, so do nothing if CreateModuleCodeFile is False
1184        if not CreateModuleCodeFile:
1185            return
1186
1187        for Ma in self.ModuleAutoGenList:
1188            Ma.CreateCodeFile(True)
1189
1190    ## Generate Fds Command
1191    @cached_property
1192    def GenFdsCommand(self):
1193        return self.Workspace.GenFdsCommand
1194
1195    ## Create makefile for the platform and modules in it
1196    #
1197    #   @param      CreateModuleMakeFile    Flag indicating if the makefile for
1198    #                                       modules will be created as well
1199    #
1200    def CreateMakeFile(self, CreateModuleMakeFile=False, FfsCommand = {}):
1201        if CreateModuleMakeFile:
1202            for Ma in self._MaList:
1203                key = (Ma.MetaFile.File, self.Arch)
1204                if key in FfsCommand:
1205                    Ma.CreateMakeFile(True, FfsCommand[key])
1206                else:
1207                    Ma.CreateMakeFile(True)
1208
1209        # no need to create makefile for the platform more than once
1210        if self.IsMakeFileCreated:
1211            return
1212
1213        # create library/module build dirs for platform
1214        Makefile = GenMake.PlatformMakefile(self)
1215        self.LibraryBuildDirectoryList = Makefile.GetLibraryBuildDirectoryList()
1216        self.ModuleBuildDirectoryList = Makefile.GetModuleBuildDirectoryList()
1217
1218        self.IsMakeFileCreated = True
1219
1220    @property
1221    def AllPcdList(self):
1222        return self.DynamicPcdList + self.NonDynamicPcdList
1223    ## Deal with Shared FixedAtBuild Pcds
1224    #
1225    def CollectFixedAtBuildPcds(self):
1226        for LibAuto in self.LibraryAutoGenList:
1227            FixedAtBuildPcds = {}
1228            ShareFixedAtBuildPcdsSameValue = {}
1229            for Module in LibAuto.ReferenceModules:
1230                for Pcd in set(Module.FixedAtBuildPcds + LibAuto.FixedAtBuildPcds):
1231                    DefaultValue = Pcd.DefaultValue
1232                    # Cover the case: DSC component override the Pcd value and the Pcd only used in one Lib
1233                    if Pcd in Module.LibraryPcdList:
1234                        Index = Module.LibraryPcdList.index(Pcd)
1235                        DefaultValue = Module.LibraryPcdList[Index].DefaultValue
1236                    key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1237                    if key not in FixedAtBuildPcds:
1238                        ShareFixedAtBuildPcdsSameValue[key] = True
1239                        FixedAtBuildPcds[key] = DefaultValue
1240                    else:
1241                        if FixedAtBuildPcds[key] != DefaultValue:
1242                            ShareFixedAtBuildPcdsSameValue[key] = False
1243            for Pcd in LibAuto.FixedAtBuildPcds:
1244                key = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1245                if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) not in self.NonDynamicPcdDict:
1246                    continue
1247                else:
1248                    DscPcd = self.NonDynamicPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)]
1249                    if DscPcd.Type != TAB_PCDS_FIXED_AT_BUILD:
1250                        continue
1251                if key in ShareFixedAtBuildPcdsSameValue and ShareFixedAtBuildPcdsSameValue[key]:
1252                    LibAuto.ConstPcd[key] = FixedAtBuildPcds[key]
1253
1254    def CollectVariables(self, DynamicPcdSet):
1255        VpdRegionSize = 0
1256        VpdRegionBase = 0
1257        if self.Workspace.FdfFile:
1258            FdDict = self.Workspace.FdfProfile.FdDict[GlobalData.gFdfParser.CurrentFdName]
1259            for FdRegion in FdDict.RegionList:
1260                for item in FdRegion.RegionDataList:
1261                    if self.Platform.VpdToolGuid.strip() and self.Platform.VpdToolGuid in item:
1262                        VpdRegionSize = FdRegion.Size
1263                        VpdRegionBase = FdRegion.Offset
1264                        break
1265
1266        VariableInfo = VariableMgr(self.DscBuildDataObj._GetDefaultStores(), self.DscBuildDataObj.SkuIds)
1267        VariableInfo.SetVpdRegionMaxSize(VpdRegionSize)
1268        VariableInfo.SetVpdRegionOffset(VpdRegionBase)
1269        Index = 0
1270        for Pcd in DynamicPcdSet:
1271            pcdname = ".".join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1272            for SkuName in Pcd.SkuInfoList:
1273                Sku = Pcd.SkuInfoList[SkuName]
1274                SkuId = Sku.SkuId
1275                if SkuId is None or SkuId == '':
1276                    continue
1277                if len(Sku.VariableName) > 0:
1278                    if Sku.VariableAttribute and 'NV' not in Sku.VariableAttribute:
1279                        continue
1280                    VariableGuidStructure = Sku.VariableGuidValue
1281                    VariableGuid = GuidStructureStringToGuidString(VariableGuidStructure)
1282                    for StorageName in Sku.DefaultStoreDict:
1283                        VariableInfo.append_variable(var_info(Index, pcdname, StorageName, SkuName, StringToArray(Sku.VariableName), VariableGuid, Sku.VariableOffset, Sku.VariableAttribute, Sku.HiiDefaultValue, Sku.DefaultStoreDict[StorageName] if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES else StringToArray(Sku.DefaultStoreDict[StorageName]), Pcd.DatumType, Pcd.CustomAttribute['DscPosition'], Pcd.CustomAttribute.get('IsStru',False)))
1284            Index += 1
1285        return VariableInfo
1286
1287    def UpdateNVStoreMaxSize(self, OrgVpdFile):
1288        if self.VariableInfo:
1289            VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
1290            PcdNvStoreDfBuffer = [item for item in self._DynamicPcdList if item.TokenCName == "PcdNvStoreDefaultValueBuffer" and item.TokenSpaceGuidCName == "gEfiMdeModulePkgTokenSpaceGuid"]
1291
1292            if PcdNvStoreDfBuffer:
1293                if os.path.exists(VpdMapFilePath):
1294                    OrgVpdFile.Read(VpdMapFilePath)
1295                    PcdItems = OrgVpdFile.GetOffset(PcdNvStoreDfBuffer[0])
1296                    NvStoreOffset = list(PcdItems.values())[0].strip() if PcdItems else '0'
1297                else:
1298                    EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
1299
1300                NvStoreOffset = int(NvStoreOffset, 16) if NvStoreOffset.upper().startswith("0X") else int(NvStoreOffset)
1301                default_skuobj = PcdNvStoreDfBuffer[0].SkuInfoList.get(TAB_DEFAULT)
1302                maxsize = self.VariableInfo.VpdRegionSize  - NvStoreOffset if self.VariableInfo.VpdRegionSize else len(default_skuobj.DefaultValue.split(","))
1303                var_data = self.VariableInfo.PatchNVStoreDefaultMaxSize(maxsize)
1304
1305                if var_data and default_skuobj:
1306                    default_skuobj.DefaultValue = var_data
1307                    PcdNvStoreDfBuffer[0].DefaultValue = var_data
1308                    PcdNvStoreDfBuffer[0].SkuInfoList.clear()
1309                    PcdNvStoreDfBuffer[0].SkuInfoList[TAB_DEFAULT] = default_skuobj
1310                    PcdNvStoreDfBuffer[0].MaxDatumSize = str(len(default_skuobj.DefaultValue.split(",")))
1311
1312        return OrgVpdFile
1313
1314    ## Collect dynamic PCDs
1315    #
1316    #  Gather dynamic PCDs list from each module and their settings from platform
1317    #  This interface should be invoked explicitly when platform action is created.
1318    #
1319    def CollectPlatformDynamicPcds(self):
1320        for key in self.Platform.Pcds:
1321            for SinglePcd in GlobalData.MixedPcd:
1322                if (self.Platform.Pcds[key].TokenCName, self.Platform.Pcds[key].TokenSpaceGuidCName) == SinglePcd:
1323                    for item in GlobalData.MixedPcd[SinglePcd]:
1324                        Pcd_Type = item[0].split('_')[-1]
1325                        if (Pcd_Type == self.Platform.Pcds[key].Type) or (Pcd_Type == TAB_PCDS_DYNAMIC_EX and self.Platform.Pcds[key].Type in PCD_DYNAMIC_EX_TYPE_SET) or \
1326                           (Pcd_Type == TAB_PCDS_DYNAMIC and self.Platform.Pcds[key].Type in PCD_DYNAMIC_TYPE_SET):
1327                            Value = self.Platform.Pcds[key]
1328                            Value.TokenCName = self.Platform.Pcds[key].TokenCName + '_' + Pcd_Type
1329                            if len(key) == 2:
1330                                newkey = (Value.TokenCName, key[1])
1331                            elif len(key) == 3:
1332                                newkey = (Value.TokenCName, key[1], key[2])
1333                            del self.Platform.Pcds[key]
1334                            self.Platform.Pcds[newkey] = Value
1335                            break
1336                    break
1337
1338        # for gathering error information
1339        NoDatumTypePcdList = set()
1340        FdfModuleList = []
1341        for InfName in self._AsBuildInfList:
1342            InfName = mws.join(self.WorkspaceDir, InfName)
1343            FdfModuleList.append(os.path.normpath(InfName))
1344        for M in self._MaList:
1345#            F is the Module for which M is the module autogen
1346            for PcdFromModule in M.ModulePcdList + M.LibraryPcdList:
1347                # make sure that the "VOID*" kind of datum has MaxDatumSize set
1348                if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
1349                    NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, M.MetaFile))
1350
1351                # Check the PCD from Binary INF or Source INF
1352                if M.IsBinaryModule == True:
1353                    PcdFromModule.IsFromBinaryInf = True
1354
1355                # Check the PCD from DSC or not
1356                PcdFromModule.IsFromDsc = (PcdFromModule.TokenCName, PcdFromModule.TokenSpaceGuidCName) in self.Platform.Pcds
1357
1358                if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET or PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1359                    if M.MetaFile.Path not in FdfModuleList:
1360                        # If one of the Source built modules listed in the DSC is not listed
1361                        # in FDF modules, and the INF lists a PCD can only use the PcdsDynamic
1362                        # access method (it is only listed in the DEC file that declares the
1363                        # PCD as PcdsDynamic), then build tool will report warning message
1364                        # notify the PI that they are attempting to build a module that must
1365                        # be included in a flash image in order to be functional. These Dynamic
1366                        # PCD will not be added into the Database unless it is used by other
1367                        # modules that are included in the FDF file.
1368                        if PcdFromModule.Type in PCD_DYNAMIC_TYPE_SET and \
1369                            PcdFromModule.IsFromBinaryInf == False:
1370                            # Print warning message to let the developer make a determine.
1371                            continue
1372                        # If one of the Source built modules listed in the DSC is not listed in
1373                        # FDF modules, and the INF lists a PCD can only use the PcdsDynamicEx
1374                        # access method (it is only listed in the DEC file that declares the
1375                        # PCD as PcdsDynamicEx), then DO NOT break the build; DO NOT add the
1376                        # PCD to the Platform's PCD Database.
1377                        if PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1378                            continue
1379                    #
1380                    # If a dynamic PCD used by a PEM module/PEI module & DXE module,
1381                    # it should be stored in Pcd PEI database, If a dynamic only
1382                    # used by DXE module, it should be stored in DXE PCD database.
1383                    # The default Phase is DXE
1384                    #
1385                    if M.ModuleType in SUP_MODULE_SET_PEI:
1386                        PcdFromModule.Phase = "PEI"
1387                    if PcdFromModule not in self._DynaPcdList_:
1388                        self._DynaPcdList_.append(PcdFromModule)
1389                    elif PcdFromModule.Phase == 'PEI':
1390                        # overwrite any the same PCD existing, if Phase is PEI
1391                        Index = self._DynaPcdList_.index(PcdFromModule)
1392                        self._DynaPcdList_[Index] = PcdFromModule
1393                elif PcdFromModule not in self._NonDynaPcdList_:
1394                    self._NonDynaPcdList_.append(PcdFromModule)
1395                elif PcdFromModule in self._NonDynaPcdList_ and PcdFromModule.IsFromBinaryInf == True:
1396                    Index = self._NonDynaPcdList_.index(PcdFromModule)
1397                    if self._NonDynaPcdList_[Index].IsFromBinaryInf == False:
1398                        #The PCD from Binary INF will override the same one from source INF
1399                        self._NonDynaPcdList_.remove (self._NonDynaPcdList_[Index])
1400                        PcdFromModule.Pending = False
1401                        self._NonDynaPcdList_.append (PcdFromModule)
1402        DscModuleSet = {os.path.normpath(ModuleInf.Path) for ModuleInf in self.Platform.Modules}
1403        # add the PCD from modules that listed in FDF but not in DSC to Database
1404        for InfName in FdfModuleList:
1405            if InfName not in DscModuleSet:
1406                InfClass = PathClass(InfName)
1407                M = self.BuildDatabase[InfClass, self.Arch, self.BuildTarget, self.ToolChain]
1408                # If a module INF in FDF but not in current arch's DSC module list, it must be module (either binary or source)
1409                # for different Arch. PCDs in source module for different Arch is already added before, so skip the source module here.
1410                # For binary module, if in current arch, we need to list the PCDs into database.
1411                if not M.IsBinaryModule:
1412                    continue
1413                # Override the module PCD setting by platform setting
1414                ModulePcdList = self.ApplyPcdSetting(M, M.Pcds)
1415                for PcdFromModule in ModulePcdList:
1416                    PcdFromModule.IsFromBinaryInf = True
1417                    PcdFromModule.IsFromDsc = False
1418                    # Only allow the DynamicEx and Patchable PCD in AsBuild INF
1419                    if PcdFromModule.Type not in PCD_DYNAMIC_EX_TYPE_SET and PcdFromModule.Type not in TAB_PCDS_PATCHABLE_IN_MODULE:
1420                        EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
1421                                        File=self.MetaFile,
1422                                        ExtraData="\n\tExisted %s PCD %s in:\n\t\t%s\n"
1423                                        % (PcdFromModule.Type, PcdFromModule.TokenCName, InfName))
1424                    # make sure that the "VOID*" kind of datum has MaxDatumSize set
1425                    if PcdFromModule.DatumType == TAB_VOID and not PcdFromModule.MaxDatumSize:
1426                        NoDatumTypePcdList.add("%s.%s [%s]" % (PcdFromModule.TokenSpaceGuidCName, PcdFromModule.TokenCName, InfName))
1427                    if M.ModuleType in SUP_MODULE_SET_PEI:
1428                        PcdFromModule.Phase = "PEI"
1429                    if PcdFromModule not in self._DynaPcdList_ and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1430                        self._DynaPcdList_.append(PcdFromModule)
1431                    elif PcdFromModule not in self._NonDynaPcdList_ and PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE:
1432                        self._NonDynaPcdList_.append(PcdFromModule)
1433                    if PcdFromModule in self._DynaPcdList_ and PcdFromModule.Phase == 'PEI' and PcdFromModule.Type in PCD_DYNAMIC_EX_TYPE_SET:
1434                        # Overwrite the phase of any the same PCD existing, if Phase is PEI.
1435                        # It is to solve the case that a dynamic PCD used by a PEM module/PEI
1436                        # module & DXE module at a same time.
1437                        # Overwrite the type of the PCDs in source INF by the type of AsBuild
1438                        # INF file as DynamicEx.
1439                        Index = self._DynaPcdList_.index(PcdFromModule)
1440                        self._DynaPcdList_[Index].Phase = PcdFromModule.Phase
1441                        self._DynaPcdList_[Index].Type = PcdFromModule.Type
1442        for PcdFromModule in self._NonDynaPcdList_:
1443            # If a PCD is not listed in the DSC file, but binary INF files used by
1444            # this platform all (that use this PCD) list the PCD in a [PatchPcds]
1445            # section, AND all source INF files used by this platform the build
1446            # that use the PCD list the PCD in either a [Pcds] or [PatchPcds]
1447            # section, then the tools must NOT add the PCD to the Platform's PCD
1448            # Database; the build must assign the access method for this PCD as
1449            # PcdsPatchableInModule.
1450            if PcdFromModule not in self._DynaPcdList_:
1451                continue
1452            Index = self._DynaPcdList_.index(PcdFromModule)
1453            if PcdFromModule.IsFromDsc == False and \
1454                PcdFromModule.Type in TAB_PCDS_PATCHABLE_IN_MODULE and \
1455                PcdFromModule.IsFromBinaryInf == True and \
1456                self._DynaPcdList_[Index].IsFromBinaryInf == False:
1457                Index = self._DynaPcdList_.index(PcdFromModule)
1458                self._DynaPcdList_.remove (self._DynaPcdList_[Index])
1459
1460        # print out error information and break the build, if error found
1461        if len(NoDatumTypePcdList) > 0:
1462            NoDatumTypePcdListString = "\n\t\t".join(NoDatumTypePcdList)
1463            EdkLogger.error("build", AUTOGEN_ERROR, "PCD setting error",
1464                            File=self.MetaFile,
1465                            ExtraData="\n\tPCD(s) without MaxDatumSize:\n\t\t%s\n"
1466                                      % NoDatumTypePcdListString)
1467        self._NonDynamicPcdList = self._NonDynaPcdList_
1468        self._DynamicPcdList = self._DynaPcdList_
1469        #
1470        # Sort dynamic PCD list to:
1471        # 1) If PCD's datum type is VOID* and value is unicode string which starts with L, the PCD item should
1472        #    try to be put header of dynamicd List
1473        # 2) If PCD is HII type, the PCD item should be put after unicode type PCD
1474        #
1475        # The reason of sorting is make sure the unicode string is in double-byte alignment in string table.
1476        #
1477        UnicodePcdArray = set()
1478        HiiPcdArray     = set()
1479        OtherPcdArray   = set()
1480        VpdPcdDict      = {}
1481        VpdFile               = VpdInfoFile.VpdInfoFile()
1482        NeedProcessVpdMapFile = False
1483
1484        for pcd in self.Platform.Pcds:
1485            if pcd not in self._PlatformPcds:
1486                self._PlatformPcds[pcd] = self.Platform.Pcds[pcd]
1487
1488        for item in self._PlatformPcds:
1489            if self._PlatformPcds[item].DatumType and self._PlatformPcds[item].DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1490                self._PlatformPcds[item].DatumType = TAB_VOID
1491
1492        if (self.Workspace.ArchList[-1] == self.Arch):
1493            for Pcd in self._DynamicPcdList:
1494                # just pick the a value to determine whether is unicode string type
1495                Sku = Pcd.SkuInfoList.get(TAB_DEFAULT)
1496                Sku.VpdOffset = Sku.VpdOffset.strip()
1497
1498                if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1499                    Pcd.DatumType = TAB_VOID
1500
1501                    # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
1502                    # if found HII type PCD then insert to right of UnicodeIndex
1503                if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
1504                    VpdPcdDict[(Pcd.TokenCName, Pcd.TokenSpaceGuidCName)] = Pcd
1505
1506            #Collect DynamicHii PCD values and assign it to DynamicExVpd PCD gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer
1507            PcdNvStoreDfBuffer = VpdPcdDict.get(("PcdNvStoreDefaultValueBuffer", "gEfiMdeModulePkgTokenSpaceGuid"))
1508            if PcdNvStoreDfBuffer:
1509                self.VariableInfo = self.CollectVariables(self._DynamicPcdList)
1510                vardump = self.VariableInfo.dump()
1511                if vardump:
1512                    #
1513                    #According to PCD_DATABASE_INIT in edk2\MdeModulePkg\Include\Guid\PcdDataBaseSignatureGuid.h,
1514                    #the max size for string PCD should not exceed USHRT_MAX 65535(0xffff).
1515                    #typedef UINT16 SIZE_INFO;
1516                    #//SIZE_INFO  SizeTable[];
1517                    if len(vardump.split(",")) > 0xffff:
1518                        EdkLogger.error("build", RESOURCE_OVERFLOW, 'The current length of PCD %s value is %d, it exceeds to the max size of String PCD.' %(".".join([PcdNvStoreDfBuffer.TokenSpaceGuidCName,PcdNvStoreDfBuffer.TokenCName]) ,len(vardump.split(","))))
1519                    PcdNvStoreDfBuffer.DefaultValue = vardump
1520                    for skuname in PcdNvStoreDfBuffer.SkuInfoList:
1521                        PcdNvStoreDfBuffer.SkuInfoList[skuname].DefaultValue = vardump
1522                        PcdNvStoreDfBuffer.MaxDatumSize = str(len(vardump.split(",")))
1523            else:
1524                #If the end user define [DefaultStores] and [XXX.Menufacturing] in DSC, but forget to configure PcdNvStoreDefaultValueBuffer to PcdsDynamicVpd
1525                if [Pcd for Pcd in self._DynamicPcdList if Pcd.UserDefinedDefaultStoresFlag]:
1526                    EdkLogger.warn("build", "PcdNvStoreDefaultValueBuffer should be defined as PcdsDynamicExVpd in dsc file since the DefaultStores is enabled for this platform.\n%s" %self.Platform.MetaFile.Path)
1527            PlatformPcds = sorted(self._PlatformPcds.keys())
1528            #
1529            # Add VPD type PCD into VpdFile and determine whether the VPD PCD need to be fixed up.
1530            #
1531            VpdSkuMap = {}
1532            for PcdKey in PlatformPcds:
1533                Pcd = self._PlatformPcds[PcdKey]
1534                if Pcd.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD] and \
1535                   PcdKey in VpdPcdDict:
1536                    Pcd = VpdPcdDict[PcdKey]
1537                    SkuValueMap = {}
1538                    DefaultSku = Pcd.SkuInfoList.get(TAB_DEFAULT)
1539                    if DefaultSku:
1540                        PcdValue = DefaultSku.DefaultValue
1541                        if PcdValue not in SkuValueMap:
1542                            SkuValueMap[PcdValue] = []
1543                            VpdFile.Add(Pcd, TAB_DEFAULT, DefaultSku.VpdOffset)
1544                        SkuValueMap[PcdValue].append(DefaultSku)
1545
1546                    for (SkuName, Sku) in Pcd.SkuInfoList.items():
1547                        Sku.VpdOffset = Sku.VpdOffset.strip()
1548                        PcdValue = Sku.DefaultValue
1549                        if PcdValue == "":
1550                            PcdValue  = Pcd.DefaultValue
1551                        if Sku.VpdOffset != TAB_STAR:
1552                            if PcdValue.startswith("{"):
1553                                Alignment = 8
1554                            elif PcdValue.startswith("L"):
1555                                Alignment = 2
1556                            else:
1557                                Alignment = 1
1558                            try:
1559                                VpdOffset = int(Sku.VpdOffset)
1560                            except:
1561                                try:
1562                                    VpdOffset = int(Sku.VpdOffset, 16)
1563                                except:
1564                                    EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, Pcd.TokenSpaceGuidCName, Pcd.TokenCName))
1565                            if VpdOffset % Alignment != 0:
1566                                if PcdValue.startswith("{"):
1567                                    EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(Pcd.TokenSpaceGuidCName, Pcd.TokenCName), File=self.MetaFile)
1568                                else:
1569                                    EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (Pcd.TokenSpaceGuidCName, Pcd.TokenCName, Alignment))
1570                        if PcdValue not in SkuValueMap:
1571                            SkuValueMap[PcdValue] = []
1572                            VpdFile.Add(Pcd, SkuName, Sku.VpdOffset)
1573                        SkuValueMap[PcdValue].append(Sku)
1574                        # if the offset of a VPD is *, then it need to be fixed up by third party tool.
1575                        if not NeedProcessVpdMapFile and Sku.VpdOffset == TAB_STAR:
1576                            NeedProcessVpdMapFile = True
1577                            if self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == '':
1578                                EdkLogger.error("Build", FILE_NOT_FOUND, \
1579                                                "Fail to find third-party BPDG tool to process VPD PCDs. BPDG Guid tool need to be defined in tools_def.txt and VPD_TOOL_GUID need to be provided in DSC file.")
1580
1581                    VpdSkuMap[PcdKey] = SkuValueMap
1582            #
1583            # Fix the PCDs define in VPD PCD section that never referenced by module.
1584            # An example is PCD for signature usage.
1585            #
1586            for DscPcd in PlatformPcds:
1587                DscPcdEntry = self._PlatformPcds[DscPcd]
1588                if DscPcdEntry.Type in [TAB_PCDS_DYNAMIC_VPD, TAB_PCDS_DYNAMIC_EX_VPD]:
1589                    if not (self.Platform.VpdToolGuid is None or self.Platform.VpdToolGuid == ''):
1590                        FoundFlag = False
1591                        for VpdPcd in VpdFile._VpdArray:
1592                            # This PCD has been referenced by module
1593                            if (VpdPcd.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
1594                               (VpdPcd.TokenCName == DscPcdEntry.TokenCName):
1595                                    FoundFlag = True
1596
1597                        # Not found, it should be signature
1598                        if not FoundFlag :
1599                            # just pick the a value to determine whether is unicode string type
1600                            SkuValueMap = {}
1601                            SkuObjList = list(DscPcdEntry.SkuInfoList.items())
1602                            DefaultSku = DscPcdEntry.SkuInfoList.get(TAB_DEFAULT)
1603                            if DefaultSku:
1604                                defaultindex = SkuObjList.index((TAB_DEFAULT, DefaultSku))
1605                                SkuObjList[0], SkuObjList[defaultindex] = SkuObjList[defaultindex], SkuObjList[0]
1606                            for (SkuName, Sku) in SkuObjList:
1607                                Sku.VpdOffset = Sku.VpdOffset.strip()
1608
1609                                # Need to iterate DEC pcd information to get the value & datumtype
1610                                for eachDec in self.PackageList:
1611                                    for DecPcd in eachDec.Pcds:
1612                                        DecPcdEntry = eachDec.Pcds[DecPcd]
1613                                        if (DecPcdEntry.TokenSpaceGuidCName == DscPcdEntry.TokenSpaceGuidCName) and \
1614                                           (DecPcdEntry.TokenCName == DscPcdEntry.TokenCName):
1615                                            # Print warning message to let the developer make a determine.
1616                                            EdkLogger.warn("build", "Unreferenced vpd pcd used!",
1617                                                            File=self.MetaFile, \
1618                                                            ExtraData = "PCD: %s.%s used in the DSC file %s is unreferenced." \
1619                                                            %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, self.Platform.MetaFile.Path))
1620
1621                                            DscPcdEntry.DatumType    = DecPcdEntry.DatumType
1622                                            DscPcdEntry.DefaultValue = DecPcdEntry.DefaultValue
1623                                            DscPcdEntry.TokenValue = DecPcdEntry.TokenValue
1624                                            DscPcdEntry.TokenSpaceGuidValue = eachDec.Guids[DecPcdEntry.TokenSpaceGuidCName]
1625                                            # Only fix the value while no value provided in DSC file.
1626                                            if not Sku.DefaultValue:
1627                                                DscPcdEntry.SkuInfoList[list(DscPcdEntry.SkuInfoList.keys())[0]].DefaultValue = DecPcdEntry.DefaultValue
1628
1629                                if DscPcdEntry not in self._DynamicPcdList:
1630                                    self._DynamicPcdList.append(DscPcdEntry)
1631                                Sku.VpdOffset = Sku.VpdOffset.strip()
1632                                PcdValue = Sku.DefaultValue
1633                                if PcdValue == "":
1634                                    PcdValue  = DscPcdEntry.DefaultValue
1635                                if Sku.VpdOffset != TAB_STAR:
1636                                    if PcdValue.startswith("{"):
1637                                        Alignment = 8
1638                                    elif PcdValue.startswith("L"):
1639                                        Alignment = 2
1640                                    else:
1641                                        Alignment = 1
1642                                    try:
1643                                        VpdOffset = int(Sku.VpdOffset)
1644                                    except:
1645                                        try:
1646                                            VpdOffset = int(Sku.VpdOffset, 16)
1647                                        except:
1648                                            EdkLogger.error("build", FORMAT_INVALID, "Invalid offset value %s for PCD %s.%s." % (Sku.VpdOffset, DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName))
1649                                    if VpdOffset % Alignment != 0:
1650                                        if PcdValue.startswith("{"):
1651                                            EdkLogger.warn("build", "The offset value of PCD %s.%s is not 8-byte aligned!" %(DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName), File=self.MetaFile)
1652                                        else:
1653                                            EdkLogger.error("build", FORMAT_INVALID, 'The offset value of PCD %s.%s should be %s-byte aligned.' % (DscPcdEntry.TokenSpaceGuidCName, DscPcdEntry.TokenCName, Alignment))
1654                                if PcdValue not in SkuValueMap:
1655                                    SkuValueMap[PcdValue] = []
1656                                    VpdFile.Add(DscPcdEntry, SkuName, Sku.VpdOffset)
1657                                SkuValueMap[PcdValue].append(Sku)
1658                                if not NeedProcessVpdMapFile and Sku.VpdOffset == TAB_STAR:
1659                                    NeedProcessVpdMapFile = True
1660                            if DscPcdEntry.DatumType == TAB_VOID and PcdValue.startswith("L"):
1661                                UnicodePcdArray.add(DscPcdEntry)
1662                            elif len(Sku.VariableName) > 0:
1663                                HiiPcdArray.add(DscPcdEntry)
1664                            else:
1665                                OtherPcdArray.add(DscPcdEntry)
1666
1667                                # if the offset of a VPD is *, then it need to be fixed up by third party tool.
1668                            VpdSkuMap[DscPcd] = SkuValueMap
1669            if (self.Platform.FlashDefinition is None or self.Platform.FlashDefinition == '') and \
1670               VpdFile.GetCount() != 0:
1671                EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE,
1672                                "Fail to get FLASH_DEFINITION definition in DSC file %s which is required when DSC contains VPD PCD." % str(self.Platform.MetaFile))
1673
1674            if VpdFile.GetCount() != 0:
1675
1676                self.FixVpdOffset(VpdFile)
1677
1678                self.FixVpdOffset(self.UpdateNVStoreMaxSize(VpdFile))
1679                PcdNvStoreDfBuffer = [item for item in self._DynamicPcdList if item.TokenCName == "PcdNvStoreDefaultValueBuffer" and item.TokenSpaceGuidCName == "gEfiMdeModulePkgTokenSpaceGuid"]
1680                if PcdNvStoreDfBuffer:
1681                    PcdName,PcdGuid = PcdNvStoreDfBuffer[0].TokenCName, PcdNvStoreDfBuffer[0].TokenSpaceGuidCName
1682                    if (PcdName,PcdGuid) in VpdSkuMap:
1683                        DefaultSku = PcdNvStoreDfBuffer[0].SkuInfoList.get(TAB_DEFAULT)
1684                        VpdSkuMap[(PcdName,PcdGuid)] = {DefaultSku.DefaultValue:[SkuObj for SkuObj in PcdNvStoreDfBuffer[0].SkuInfoList.values() ]}
1685
1686                # Process VPD map file generated by third party BPDG tool
1687                if NeedProcessVpdMapFile:
1688                    VpdMapFilePath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY, "%s.map" % self.Platform.VpdToolGuid)
1689                    if os.path.exists(VpdMapFilePath):
1690                        VpdFile.Read(VpdMapFilePath)
1691
1692                        # Fixup TAB_STAR offset
1693                        for pcd in VpdSkuMap:
1694                            vpdinfo = VpdFile.GetVpdInfo(pcd)
1695                            if vpdinfo is None:
1696                            # just pick the a value to determine whether is unicode string type
1697                                continue
1698                            for pcdvalue in VpdSkuMap[pcd]:
1699                                for sku in VpdSkuMap[pcd][pcdvalue]:
1700                                    for item in vpdinfo:
1701                                        if item[2] == pcdvalue:
1702                                            sku.VpdOffset = item[1]
1703                    else:
1704                        EdkLogger.error("build", FILE_READ_FAILURE, "Can not find VPD map file %s to fix up VPD offset." % VpdMapFilePath)
1705
1706            # Delete the DynamicPcdList At the last time enter into this function
1707            for Pcd in self._DynamicPcdList:
1708                # just pick the a value to determine whether is unicode string type
1709                Sku = Pcd.SkuInfoList.get(TAB_DEFAULT)
1710                Sku.VpdOffset = Sku.VpdOffset.strip()
1711
1712                if Pcd.DatumType not in [TAB_UINT8, TAB_UINT16, TAB_UINT32, TAB_UINT64, TAB_VOID, "BOOLEAN"]:
1713                    Pcd.DatumType = TAB_VOID
1714
1715                PcdValue = Sku.DefaultValue
1716                if Pcd.DatumType == TAB_VOID and PcdValue.startswith("L"):
1717                    # if found PCD which datum value is unicode string the insert to left size of UnicodeIndex
1718                    UnicodePcdArray.add(Pcd)
1719                elif len(Sku.VariableName) > 0:
1720                    # if found HII type PCD then insert to right of UnicodeIndex
1721                    HiiPcdArray.add(Pcd)
1722                else:
1723                    OtherPcdArray.add(Pcd)
1724            del self._DynamicPcdList[:]
1725        self._DynamicPcdList.extend(list(UnicodePcdArray))
1726        self._DynamicPcdList.extend(list(HiiPcdArray))
1727        self._DynamicPcdList.extend(list(OtherPcdArray))
1728        allskuset = [(SkuName, Sku.SkuId) for pcd in self._DynamicPcdList for (SkuName, Sku) in pcd.SkuInfoList.items()]
1729        for pcd in self._DynamicPcdList:
1730            if len(pcd.SkuInfoList) == 1:
1731                for (SkuName, SkuId) in allskuset:
1732                    if isinstance(SkuId, str) and eval(SkuId) == 0 or SkuId == 0:
1733                        continue
1734                    pcd.SkuInfoList[SkuName] = copy.deepcopy(pcd.SkuInfoList[TAB_DEFAULT])
1735                    pcd.SkuInfoList[SkuName].SkuId = SkuId
1736                    pcd.SkuInfoList[SkuName].SkuIdName = SkuName
1737
1738    def FixVpdOffset(self, VpdFile ):
1739        FvPath = os.path.join(self.BuildDir, TAB_FV_DIRECTORY)
1740        if not os.path.exists(FvPath):
1741            try:
1742                os.makedirs(FvPath)
1743            except:
1744                EdkLogger.error("build", FILE_WRITE_FAILURE, "Fail to create FV folder under %s" % self.BuildDir)
1745
1746        VpdFilePath = os.path.join(FvPath, "%s.txt" % self.Platform.VpdToolGuid)
1747
1748        if VpdFile.Write(VpdFilePath):
1749            # retrieve BPDG tool's path from tool_def.txt according to VPD_TOOL_GUID defined in DSC file.
1750            BPDGToolName = None
1751            for ToolDef in self.ToolDefinition.values():
1752                if TAB_GUID in ToolDef and ToolDef[TAB_GUID] == self.Platform.VpdToolGuid:
1753                    if "PATH" not in ToolDef:
1754                        EdkLogger.error("build", ATTRIBUTE_NOT_AVAILABLE, "PATH attribute was not provided for BPDG guid tool %s in tools_def.txt" % self.Platform.VpdToolGuid)
1755                    BPDGToolName = ToolDef["PATH"]
1756                    break
1757            # Call third party GUID BPDG tool.
1758            if BPDGToolName is not None:
1759                VpdInfoFile.CallExtenalBPDGTool(BPDGToolName, VpdFilePath)
1760            else:
1761                EdkLogger.error("Build", FILE_NOT_FOUND, "Fail to find third-party BPDG tool to process VPD PCDs. BPDG Guid tool need to be defined in tools_def.txt and VPD_TOOL_GUID need to be provided in DSC file.")
1762
1763    ## Return the platform build data object
1764    @cached_property
1765    def Platform(self):
1766        return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
1767
1768    ## Return platform name
1769    @cached_property
1770    def Name(self):
1771        return self.Platform.PlatformName
1772
1773    ## Return the meta file GUID
1774    @cached_property
1775    def Guid(self):
1776        return self.Platform.Guid
1777
1778    ## Return the platform version
1779    @cached_property
1780    def Version(self):
1781        return self.Platform.Version
1782
1783    ## Return the FDF file name
1784    @cached_property
1785    def FdfFile(self):
1786        if self.Workspace.FdfFile:
1787            RetVal= mws.join(self.WorkspaceDir, self.Workspace.FdfFile)
1788        else:
1789            RetVal = ''
1790        return RetVal
1791
1792    ## Return the build output directory platform specifies
1793    @cached_property
1794    def OutputDir(self):
1795        return self.Platform.OutputDirectory
1796
1797    ## Return the directory to store all intermediate and final files built
1798    @cached_property
1799    def BuildDir(self):
1800        if os.path.isabs(self.OutputDir):
1801            GlobalData.gBuildDirectory = RetVal = path.join(
1802                                        path.abspath(self.OutputDir),
1803                                        self.BuildTarget + "_" + self.ToolChain,
1804                                        )
1805        else:
1806            GlobalData.gBuildDirectory = RetVal = path.join(
1807                                        self.WorkspaceDir,
1808                                        self.OutputDir,
1809                                        self.BuildTarget + "_" + self.ToolChain,
1810                                        )
1811        return RetVal
1812
1813    ## Return directory of platform makefile
1814    #
1815    #   @retval     string  Makefile directory
1816    #
1817    @cached_property
1818    def MakeFileDir(self):
1819        return path.join(self.BuildDir, self.Arch)
1820
1821    ## Return build command string
1822    #
1823    #   @retval     string  Build command string
1824    #
1825    @cached_property
1826    def BuildCommand(self):
1827        RetVal = []
1828        if "MAKE" in self.ToolDefinition and "PATH" in self.ToolDefinition["MAKE"]:
1829            RetVal += _SplitOption(self.ToolDefinition["MAKE"]["PATH"])
1830            if "FLAGS" in self.ToolDefinition["MAKE"]:
1831                NewOption = self.ToolDefinition["MAKE"]["FLAGS"].strip()
1832                if NewOption != '':
1833                    RetVal += _SplitOption(NewOption)
1834            if "MAKE" in self.EdkIIBuildOption:
1835                if "FLAGS" in self.EdkIIBuildOption["MAKE"]:
1836                    Flags = self.EdkIIBuildOption["MAKE"]["FLAGS"]
1837                    if Flags.startswith('='):
1838                        RetVal = [RetVal[0]] + [Flags[1:]]
1839                    else:
1840                        RetVal.append(Flags)
1841        return RetVal
1842
1843    ## Get tool chain definition
1844    #
1845    #  Get each tool definition for given tool chain from tools_def.txt and platform
1846    #
1847    @cached_property
1848    def ToolDefinition(self):
1849        ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDictionary
1850        if TAB_TOD_DEFINES_COMMAND_TYPE not in self.Workspace.ToolDef.ToolsDefTxtDatabase:
1851            EdkLogger.error('build', RESOURCE_NOT_AVAILABLE, "No tools found in configuration",
1852                            ExtraData="[%s]" % self.MetaFile)
1853        RetVal = {}
1854        DllPathList = set()
1855        for Def in ToolDefinition:
1856            Target, Tag, Arch, Tool, Attr = Def.split("_")
1857            if Target != self.BuildTarget or Tag != self.ToolChain or Arch != self.Arch:
1858                continue
1859
1860            Value = ToolDefinition[Def]
1861            # don't record the DLL
1862            if Attr == "DLL":
1863                DllPathList.add(Value)
1864                continue
1865
1866            if Tool not in RetVal:
1867                RetVal[Tool] = {}
1868            RetVal[Tool][Attr] = Value
1869
1870        ToolsDef = ''
1871        if GlobalData.gOptions.SilentMode and "MAKE" in RetVal:
1872            if "FLAGS" not in RetVal["MAKE"]:
1873                RetVal["MAKE"]["FLAGS"] = ""
1874            RetVal["MAKE"]["FLAGS"] += " -s"
1875        MakeFlags = ''
1876        for Tool in RetVal:
1877            for Attr in RetVal[Tool]:
1878                Value = RetVal[Tool][Attr]
1879                if Tool in self._BuildOptionWithToolDef(RetVal) and Attr in self._BuildOptionWithToolDef(RetVal)[Tool]:
1880                    # check if override is indicated
1881                    if self._BuildOptionWithToolDef(RetVal)[Tool][Attr].startswith('='):
1882                        Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr][1:]
1883                    else:
1884                        if Attr != 'PATH':
1885                            Value += " " + self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1886                        else:
1887                            Value = self._BuildOptionWithToolDef(RetVal)[Tool][Attr]
1888
1889                if Attr == "PATH":
1890                    # Don't put MAKE definition in the file
1891                    if Tool != "MAKE":
1892                        ToolsDef += "%s = %s\n" % (Tool, Value)
1893                elif Attr != "DLL":
1894                    # Don't put MAKE definition in the file
1895                    if Tool == "MAKE":
1896                        if Attr == "FLAGS":
1897                            MakeFlags = Value
1898                    else:
1899                        ToolsDef += "%s_%s = %s\n" % (Tool, Attr, Value)
1900            ToolsDef += "\n"
1901
1902        SaveFileOnChange(self.ToolDefinitionFile, ToolsDef, False)
1903        for DllPath in DllPathList:
1904            os.environ["PATH"] = DllPath + os.pathsep + os.environ["PATH"]
1905        os.environ["MAKE_FLAGS"] = MakeFlags
1906
1907        return RetVal
1908
1909    ## Return the paths of tools
1910    @cached_property
1911    def ToolDefinitionFile(self):
1912        return os.path.join(self.MakeFileDir, "TOOLS_DEF." + self.Arch)
1913
1914    ## Retrieve the toolchain family of given toolchain tag. Default to 'MSFT'.
1915    @cached_property
1916    def ToolChainFamily(self):
1917        ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1918        if TAB_TOD_DEFINES_FAMILY not in ToolDefinition \
1919           or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_FAMILY] \
1920           or not ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]:
1921            EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1922                               % self.ToolChain)
1923            RetVal = TAB_COMPILER_MSFT
1924        else:
1925            RetVal = ToolDefinition[TAB_TOD_DEFINES_FAMILY][self.ToolChain]
1926        return RetVal
1927
1928    @cached_property
1929    def BuildRuleFamily(self):
1930        ToolDefinition = self.Workspace.ToolDef.ToolsDefTxtDatabase
1931        if TAB_TOD_DEFINES_BUILDRULEFAMILY not in ToolDefinition \
1932           or self.ToolChain not in ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY] \
1933           or not ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]:
1934            EdkLogger.verbose("No tool chain family found in configuration for %s. Default to MSFT." \
1935                               % self.ToolChain)
1936            return TAB_COMPILER_MSFT
1937
1938        return ToolDefinition[TAB_TOD_DEFINES_BUILDRULEFAMILY][self.ToolChain]
1939
1940    ## Return the build options specific for all modules in this platform
1941    @cached_property
1942    def BuildOption(self):
1943        return self._ExpandBuildOption(self.Platform.BuildOptions)
1944
1945    def _BuildOptionWithToolDef(self, ToolDef):
1946        return self._ExpandBuildOption(self.Platform.BuildOptions, ToolDef=ToolDef)
1947
1948    ## Return the build options specific for EDK modules in this platform
1949    @cached_property
1950    def EdkBuildOption(self):
1951        return self._ExpandBuildOption(self.Platform.BuildOptions, EDK_NAME)
1952
1953    ## Return the build options specific for EDKII modules in this platform
1954    @cached_property
1955    def EdkIIBuildOption(self):
1956        return self._ExpandBuildOption(self.Platform.BuildOptions, EDKII_NAME)
1957
1958    ## Parse build_rule.txt in Conf Directory.
1959    #
1960    #   @retval     BuildRule object
1961    #
1962    @cached_property
1963    def BuildRule(self):
1964        BuildRuleFile = None
1965        if TAB_TAT_DEFINES_BUILD_RULE_CONF in self.Workspace.TargetTxt.TargetTxtDictionary:
1966            BuildRuleFile = self.Workspace.TargetTxt.TargetTxtDictionary[TAB_TAT_DEFINES_BUILD_RULE_CONF]
1967        if not BuildRuleFile:
1968            BuildRuleFile = gDefaultBuildRuleFile
1969        RetVal = BuildRule(BuildRuleFile)
1970        if RetVal._FileVersion == "":
1971            RetVal._FileVersion = AutoGenReqBuildRuleVerNum
1972        else:
1973            if RetVal._FileVersion < AutoGenReqBuildRuleVerNum :
1974                # If Build Rule's version is less than the version number required by the tools, halting the build.
1975                EdkLogger.error("build", AUTOGEN_ERROR,
1976                                ExtraData="The version number [%s] of build_rule.txt is less than the version number required by the AutoGen.(the minimum required version number is [%s])"\
1977                                 % (RetVal._FileVersion, AutoGenReqBuildRuleVerNum))
1978        return RetVal
1979
1980    ## Summarize the packages used by modules in this platform
1981    @cached_property
1982    def PackageList(self):
1983        RetVal = set()
1984        for La in self.LibraryAutoGenList:
1985            RetVal.update(La.DependentPackageList)
1986        for Ma in self.ModuleAutoGenList:
1987            RetVal.update(Ma.DependentPackageList)
1988        #Collect package set information from INF of FDF
1989        for ModuleFile in self._AsBuildModuleList:
1990            if ModuleFile in self.Platform.Modules:
1991                continue
1992            ModuleData = self.BuildDatabase[ModuleFile, self.Arch, self.BuildTarget, self.ToolChain]
1993            RetVal.update(ModuleData.Packages)
1994        return list(RetVal)
1995
1996    @cached_property
1997    def NonDynamicPcdDict(self):
1998        return {(Pcd.TokenCName, Pcd.TokenSpaceGuidCName):Pcd for Pcd in self.NonDynamicPcdList}
1999
2000    ## Get list of non-dynamic PCDs
2001    @property
2002    def NonDynamicPcdList(self):
2003        if not self._NonDynamicPcdList:
2004            self.CollectPlatformDynamicPcds()
2005        return self._NonDynamicPcdList
2006
2007    ## Get list of dynamic PCDs
2008    @property
2009    def DynamicPcdList(self):
2010        if not self._DynamicPcdList:
2011            self.CollectPlatformDynamicPcds()
2012        return self._DynamicPcdList
2013
2014    ## Generate Token Number for all PCD
2015    @cached_property
2016    def PcdTokenNumber(self):
2017        RetVal = OrderedDict()
2018        TokenNumber = 1
2019        #
2020        # Make the Dynamic and DynamicEx PCD use within different TokenNumber area.
2021        # Such as:
2022        #
2023        # Dynamic PCD:
2024        # TokenNumber 0 ~ 10
2025        # DynamicEx PCD:
2026        # TokeNumber 11 ~ 20
2027        #
2028        for Pcd in self.DynamicPcdList:
2029            if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
2030                EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
2031                RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
2032                TokenNumber += 1
2033
2034        for Pcd in self.DynamicPcdList:
2035            if Pcd.Phase == "PEI" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
2036                EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
2037                RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
2038                TokenNumber += 1
2039
2040        for Pcd in self.DynamicPcdList:
2041            if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_TYPE_SET:
2042                EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
2043                RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
2044                TokenNumber += 1
2045
2046        for Pcd in self.DynamicPcdList:
2047            if Pcd.Phase == "DXE" and Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
2048                EdkLogger.debug(EdkLogger.DEBUG_5, "%s %s (%s) -> %d" % (Pcd.TokenCName, Pcd.TokenSpaceGuidCName, Pcd.Phase, TokenNumber))
2049                RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
2050                TokenNumber += 1
2051
2052        for Pcd in self.NonDynamicPcdList:
2053            RetVal[Pcd.TokenCName, Pcd.TokenSpaceGuidCName] = TokenNumber
2054            TokenNumber += 1
2055        return RetVal
2056
2057    @cached_property
2058    def _MaList(self):
2059        for ModuleFile in self.Platform.Modules:
2060            Ma = ModuleAutoGen(
2061                  self.Workspace,
2062                  ModuleFile,
2063                  self.BuildTarget,
2064                  self.ToolChain,
2065                  self.Arch,
2066                  self.MetaFile
2067                  )
2068            self.Platform.Modules[ModuleFile].M = Ma
2069        return [x.M for x in self.Platform.Modules.values()]
2070
2071    ## Summarize ModuleAutoGen objects of all modules to be built for this platform
2072    @cached_property
2073    def ModuleAutoGenList(self):
2074        RetVal = []
2075        for Ma in self._MaList:
2076            if Ma not in RetVal:
2077                RetVal.append(Ma)
2078        return RetVal
2079
2080    ## Summarize ModuleAutoGen objects of all libraries to be built for this platform
2081    @cached_property
2082    def LibraryAutoGenList(self):
2083        RetVal = []
2084        for Ma in self._MaList:
2085            for La in Ma.LibraryAutoGenList:
2086                if La not in RetVal:
2087                    RetVal.append(La)
2088                if Ma not in La.ReferenceModules:
2089                    La.ReferenceModules.append(Ma)
2090        return RetVal
2091
2092    ## Test if a module is supported by the platform
2093    #
2094    #  An error will be raised directly if the module or its arch is not supported
2095    #  by the platform or current configuration
2096    #
2097    def ValidModule(self, Module):
2098        return Module in self.Platform.Modules or Module in self.Platform.LibraryInstances \
2099            or Module in self._AsBuildModuleList
2100
2101    ## Resolve the library classes in a module to library instances
2102    #
2103    # This method will not only resolve library classes but also sort the library
2104    # instances according to the dependency-ship.
2105    #
2106    #   @param  Module      The module from which the library classes will be resolved
2107    #
2108    #   @retval library_list    List of library instances sorted
2109    #
2110    def ApplyLibraryInstance(self, Module):
2111        # Cover the case that the binary INF file is list in the FDF file but not DSC file, return empty list directly
2112        if str(Module) not in self.Platform.Modules:
2113            return []
2114
2115        return GetModuleLibInstances(Module,
2116                                     self.Platform,
2117                                     self.BuildDatabase,
2118                                     self.Arch,
2119                                     self.BuildTarget,
2120                                     self.ToolChain,
2121                                     self.MetaFile,
2122                                     EdkLogger)
2123
2124    ## Override PCD setting (type, value, ...)
2125    #
2126    #   @param  ToPcd       The PCD to be overridden
2127    #   @param  FromPcd     The PCD overriding from
2128    #
2129    def _OverridePcd(self, ToPcd, FromPcd, Module="", Msg="", Library=""):
2130        #
2131        # in case there's PCDs coming from FDF file, which have no type given.
2132        # at this point, ToPcd.Type has the type found from dependent
2133        # package
2134        #
2135        TokenCName = ToPcd.TokenCName
2136        for PcdItem in GlobalData.MixedPcd:
2137            if (ToPcd.TokenCName, ToPcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
2138                TokenCName = PcdItem[0]
2139                break
2140        if FromPcd is not None:
2141            if ToPcd.Pending and FromPcd.Type:
2142                ToPcd.Type = FromPcd.Type
2143            elif ToPcd.Type and FromPcd.Type\
2144                and ToPcd.Type != FromPcd.Type and ToPcd.Type in FromPcd.Type:
2145                if ToPcd.Type.strip() == TAB_PCDS_DYNAMIC_EX:
2146                    ToPcd.Type = FromPcd.Type
2147            elif ToPcd.Type and FromPcd.Type \
2148                and ToPcd.Type != FromPcd.Type:
2149                if Library:
2150                    Module = str(Module) + " 's library file (" + str(Library) + ")"
2151                EdkLogger.error("build", OPTION_CONFLICT, "Mismatched PCD type",
2152                                ExtraData="%s.%s is used as [%s] in module %s, but as [%s] in %s."\
2153                                          % (ToPcd.TokenSpaceGuidCName, TokenCName,
2154                                             ToPcd.Type, Module, FromPcd.Type, Msg),
2155                                          File=self.MetaFile)
2156
2157            if FromPcd.MaxDatumSize:
2158                ToPcd.MaxDatumSize = FromPcd.MaxDatumSize
2159                ToPcd.MaxSizeUserSet = FromPcd.MaxDatumSize
2160            if FromPcd.DefaultValue:
2161                ToPcd.DefaultValue = FromPcd.DefaultValue
2162            if FromPcd.TokenValue:
2163                ToPcd.TokenValue = FromPcd.TokenValue
2164            if FromPcd.DatumType:
2165                ToPcd.DatumType = FromPcd.DatumType
2166            if FromPcd.SkuInfoList:
2167                ToPcd.SkuInfoList = FromPcd.SkuInfoList
2168            if FromPcd.UserDefinedDefaultStoresFlag:
2169                ToPcd.UserDefinedDefaultStoresFlag = FromPcd.UserDefinedDefaultStoresFlag
2170            # Add Flexible PCD format parse
2171            if ToPcd.DefaultValue:
2172                try:
2173                    ToPcd.DefaultValue = ValueExpressionEx(ToPcd.DefaultValue, ToPcd.DatumType, self.Workspace._GuidDict)(True)
2174                except BadExpression as Value:
2175                    EdkLogger.error('Parser', FORMAT_INVALID, 'PCD [%s.%s] Value "%s", %s' %(ToPcd.TokenSpaceGuidCName, ToPcd.TokenCName, ToPcd.DefaultValue, Value),
2176                                        File=self.MetaFile)
2177
2178            # check the validation of datum
2179            IsValid, Cause = CheckPcdDatum(ToPcd.DatumType, ToPcd.DefaultValue)
2180            if not IsValid:
2181                EdkLogger.error('build', FORMAT_INVALID, Cause, File=self.MetaFile,
2182                                ExtraData="%s.%s" % (ToPcd.TokenSpaceGuidCName, TokenCName))
2183            ToPcd.validateranges = FromPcd.validateranges
2184            ToPcd.validlists = FromPcd.validlists
2185            ToPcd.expressions = FromPcd.expressions
2186            ToPcd.CustomAttribute = FromPcd.CustomAttribute
2187
2188        if FromPcd is not None and ToPcd.DatumType == TAB_VOID and not ToPcd.MaxDatumSize:
2189            EdkLogger.debug(EdkLogger.DEBUG_9, "No MaxDatumSize specified for PCD %s.%s" \
2190                            % (ToPcd.TokenSpaceGuidCName, TokenCName))
2191            Value = ToPcd.DefaultValue
2192            if not Value:
2193                ToPcd.MaxDatumSize = '1'
2194            elif Value[0] == 'L':
2195                ToPcd.MaxDatumSize = str((len(Value) - 2) * 2)
2196            elif Value[0] == '{':
2197                ToPcd.MaxDatumSize = str(len(Value.split(',')))
2198            else:
2199                ToPcd.MaxDatumSize = str(len(Value) - 1)
2200
2201        # apply default SKU for dynamic PCDS if specified one is not available
2202        if (ToPcd.Type in PCD_DYNAMIC_TYPE_SET or ToPcd.Type in PCD_DYNAMIC_EX_TYPE_SET) \
2203            and not ToPcd.SkuInfoList:
2204            if self.Platform.SkuName in self.Platform.SkuIds:
2205                SkuName = self.Platform.SkuName
2206            else:
2207                SkuName = TAB_DEFAULT
2208            ToPcd.SkuInfoList = {
2209                SkuName : SkuInfoClass(SkuName, self.Platform.SkuIds[SkuName][0], '', '', '', '', '', ToPcd.DefaultValue)
2210            }
2211
2212    ## Apply PCD setting defined platform to a module
2213    #
2214    #   @param  Module  The module from which the PCD setting will be overridden
2215    #
2216    #   @retval PCD_list    The list PCDs with settings from platform
2217    #
2218    def ApplyPcdSetting(self, Module, Pcds, Library=""):
2219        # for each PCD in module
2220        for Name, Guid in Pcds:
2221            PcdInModule = Pcds[Name, Guid]
2222            # find out the PCD setting in platform
2223            if (Name, Guid) in self.Platform.Pcds:
2224                PcdInPlatform = self.Platform.Pcds[Name, Guid]
2225            else:
2226                PcdInPlatform = None
2227            # then override the settings if any
2228            self._OverridePcd(PcdInModule, PcdInPlatform, Module, Msg="DSC PCD sections", Library=Library)
2229            # resolve the VariableGuid value
2230            for SkuId in PcdInModule.SkuInfoList:
2231                Sku = PcdInModule.SkuInfoList[SkuId]
2232                if Sku.VariableGuid == '': continue
2233                Sku.VariableGuidValue = GuidValue(Sku.VariableGuid, self.PackageList, self.MetaFile.Path)
2234                if Sku.VariableGuidValue is None:
2235                    PackageList = "\n\t".join(str(P) for P in self.PackageList)
2236                    EdkLogger.error(
2237                                'build',
2238                                RESOURCE_NOT_AVAILABLE,
2239                                "Value of GUID [%s] is not found in" % Sku.VariableGuid,
2240                                ExtraData=PackageList + "\n\t(used with %s.%s from module %s)" \
2241                                                        % (Guid, Name, str(Module)),
2242                                File=self.MetaFile
2243                                )
2244
2245        # override PCD settings with module specific setting
2246        if Module in self.Platform.Modules:
2247            PlatformModule = self.Platform.Modules[str(Module)]
2248            for Key  in PlatformModule.Pcds:
2249                if GlobalData.BuildOptionPcd:
2250                    for pcd in GlobalData.BuildOptionPcd:
2251                        (TokenSpaceGuidCName, TokenCName, FieldName, pcdvalue, _) = pcd
2252                        if (TokenCName, TokenSpaceGuidCName) == Key and FieldName =="":
2253                            PlatformModule.Pcds[Key].DefaultValue = pcdvalue
2254                            PlatformModule.Pcds[Key].PcdValueFromComm = pcdvalue
2255                            break
2256                Flag = False
2257                if Key in Pcds:
2258                    ToPcd = Pcds[Key]
2259                    Flag = True
2260                elif Key in GlobalData.MixedPcd:
2261                    for PcdItem in GlobalData.MixedPcd[Key]:
2262                        if PcdItem in Pcds:
2263                            ToPcd = Pcds[PcdItem]
2264                            Flag = True
2265                            break
2266                if Flag:
2267                    self._OverridePcd(ToPcd, PlatformModule.Pcds[Key], Module, Msg="DSC Components Module scoped PCD section", Library=Library)
2268        # use PCD value to calculate the MaxDatumSize when it is not specified
2269        for Name, Guid in Pcds:
2270            Pcd = Pcds[Name, Guid]
2271            if Pcd.DatumType == TAB_VOID and not Pcd.MaxDatumSize:
2272                Pcd.MaxSizeUserSet = None
2273                Value = Pcd.DefaultValue
2274                if not Value:
2275                    Pcd.MaxDatumSize = '1'
2276                elif Value[0] == 'L':
2277                    Pcd.MaxDatumSize = str((len(Value) - 2) * 2)
2278                elif Value[0] == '{':
2279                    Pcd.MaxDatumSize = str(len(Value.split(',')))
2280                else:
2281                    Pcd.MaxDatumSize = str(len(Value) - 1)
2282        return list(Pcds.values())
2283
2284
2285
2286    ## Calculate the priority value of the build option
2287    #
2288    # @param    Key    Build option definition contain: TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
2289    #
2290    # @retval   Value  Priority value based on the priority list.
2291    #
2292    def CalculatePriorityValue(self, Key):
2293        Target, ToolChain, Arch, CommandType, Attr = Key.split('_')
2294        PriorityValue = 0x11111
2295        if Target == TAB_STAR:
2296            PriorityValue &= 0x01111
2297        if ToolChain == TAB_STAR:
2298            PriorityValue &= 0x10111
2299        if Arch == TAB_STAR:
2300            PriorityValue &= 0x11011
2301        if CommandType == TAB_STAR:
2302            PriorityValue &= 0x11101
2303        if Attr == TAB_STAR:
2304            PriorityValue &= 0x11110
2305
2306        return self.PrioList["0x%0.5x" % PriorityValue]
2307
2308
2309    ## Expand * in build option key
2310    #
2311    #   @param  Options     Options to be expanded
2312    #   @param  ToolDef     Use specified ToolDef instead of full version.
2313    #                       This is needed during initialization to prevent
2314    #                       infinite recursion betweeh BuildOptions,
2315    #                       ToolDefinition, and this function.
2316    #
2317    #   @retval options     Options expanded
2318    #
2319    def _ExpandBuildOption(self, Options, ModuleStyle=None, ToolDef=None):
2320        if not ToolDef:
2321            ToolDef = self.ToolDefinition
2322        BuildOptions = {}
2323        FamilyMatch  = False
2324        FamilyIsNull = True
2325
2326        OverrideList = {}
2327        #
2328        # Construct a list contain the build options which need override.
2329        #
2330        for Key in Options:
2331            #
2332            # Key[0] -- tool family
2333            # Key[1] -- TARGET_TOOLCHAIN_ARCH_COMMANDTYPE_ATTRIBUTE
2334            #
2335            if (Key[0] == self.BuildRuleFamily and
2336                (ModuleStyle is None or len(Key) < 3 or (len(Key) > 2 and Key[2] == ModuleStyle))):
2337                Target, ToolChain, Arch, CommandType, Attr = Key[1].split('_')
2338                if (Target == self.BuildTarget or Target == TAB_STAR) and\
2339                    (ToolChain == self.ToolChain or ToolChain == TAB_STAR) and\
2340                    (Arch == self.Arch or Arch == TAB_STAR) and\
2341                    Options[Key].startswith("="):
2342
2343                    if OverrideList.get(Key[1]) is not None:
2344                        OverrideList.pop(Key[1])
2345                    OverrideList[Key[1]] = Options[Key]
2346
2347        #
2348        # Use the highest priority value.
2349        #
2350        if (len(OverrideList) >= 2):
2351            KeyList = list(OverrideList.keys())
2352            for Index in range(len(KeyList)):
2353                NowKey = KeyList[Index]
2354                Target1, ToolChain1, Arch1, CommandType1, Attr1 = NowKey.split("_")
2355                for Index1 in range(len(KeyList) - Index - 1):
2356                    NextKey = KeyList[Index1 + Index + 1]
2357                    #
2358                    # Compare two Key, if one is included by another, choose the higher priority one
2359                    #
2360                    Target2, ToolChain2, Arch2, CommandType2, Attr2 = NextKey.split("_")
2361                    if (Target1 == Target2 or Target1 == TAB_STAR or Target2 == TAB_STAR) and\
2362                        (ToolChain1 == ToolChain2 or ToolChain1 == TAB_STAR or ToolChain2 == TAB_STAR) and\
2363                        (Arch1 == Arch2 or Arch1 == TAB_STAR or Arch2 == TAB_STAR) and\
2364                        (CommandType1 == CommandType2 or CommandType1 == TAB_STAR or CommandType2 == TAB_STAR) and\
2365                        (Attr1 == Attr2 or Attr1 == TAB_STAR or Attr2 == TAB_STAR):
2366
2367                        if self.CalculatePriorityValue(NowKey) > self.CalculatePriorityValue(NextKey):
2368                            if Options.get((self.BuildRuleFamily, NextKey)) is not None:
2369                                Options.pop((self.BuildRuleFamily, NextKey))
2370                        else:
2371                            if Options.get((self.BuildRuleFamily, NowKey)) is not None:
2372                                Options.pop((self.BuildRuleFamily, NowKey))
2373
2374        for Key in Options:
2375            if ModuleStyle is not None and len (Key) > 2:
2376                # Check Module style is EDK or EDKII.
2377                # Only append build option for the matched style module.
2378                if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
2379                    continue
2380                elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
2381                    continue
2382            Family = Key[0]
2383            Target, Tag, Arch, Tool, Attr = Key[1].split("_")
2384            # if tool chain family doesn't match, skip it
2385            if Tool in ToolDef and Family != "":
2386                FamilyIsNull = False
2387                if ToolDef[Tool].get(TAB_TOD_DEFINES_BUILDRULEFAMILY, "") != "":
2388                    if Family != ToolDef[Tool][TAB_TOD_DEFINES_BUILDRULEFAMILY]:
2389                        continue
2390                elif Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
2391                    continue
2392                FamilyMatch = True
2393            # expand any wildcard
2394            if Target == TAB_STAR or Target == self.BuildTarget:
2395                if Tag == TAB_STAR or Tag == self.ToolChain:
2396                    if Arch == TAB_STAR or Arch == self.Arch:
2397                        if Tool not in BuildOptions:
2398                            BuildOptions[Tool] = {}
2399                        if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
2400                            BuildOptions[Tool][Attr] = Options[Key]
2401                        else:
2402                            # append options for the same tool except PATH
2403                            if Attr != 'PATH':
2404                                BuildOptions[Tool][Attr] += " " + Options[Key]
2405                            else:
2406                                BuildOptions[Tool][Attr] = Options[Key]
2407        # Build Option Family has been checked, which need't to be checked again for family.
2408        if FamilyMatch or FamilyIsNull:
2409            return BuildOptions
2410
2411        for Key in Options:
2412            if ModuleStyle is not None and len (Key) > 2:
2413                # Check Module style is EDK or EDKII.
2414                # Only append build option for the matched style module.
2415                if ModuleStyle == EDK_NAME and Key[2] != EDK_NAME:
2416                    continue
2417                elif ModuleStyle == EDKII_NAME and Key[2] != EDKII_NAME:
2418                    continue
2419            Family = Key[0]
2420            Target, Tag, Arch, Tool, Attr = Key[1].split("_")
2421            # if tool chain family doesn't match, skip it
2422            if Tool not in ToolDef or Family == "":
2423                continue
2424            # option has been added before
2425            if Family != ToolDef[Tool][TAB_TOD_DEFINES_FAMILY]:
2426                continue
2427
2428            # expand any wildcard
2429            if Target == TAB_STAR or Target == self.BuildTarget:
2430                if Tag == TAB_STAR or Tag == self.ToolChain:
2431                    if Arch == TAB_STAR or Arch == self.Arch:
2432                        if Tool not in BuildOptions:
2433                            BuildOptions[Tool] = {}
2434                        if Attr != "FLAGS" or Attr not in BuildOptions[Tool] or Options[Key].startswith('='):
2435                            BuildOptions[Tool][Attr] = Options[Key]
2436                        else:
2437                            # append options for the same tool except PATH
2438                            if Attr != 'PATH':
2439                                BuildOptions[Tool][Attr] += " " + Options[Key]
2440                            else:
2441                                BuildOptions[Tool][Attr] = Options[Key]
2442        return BuildOptions
2443
2444    ## Append build options in platform to a module
2445    #
2446    #   @param  Module  The module to which the build options will be appended
2447    #
2448    #   @retval options     The options appended with build options in platform
2449    #
2450    def ApplyBuildOption(self, Module):
2451        # Get the different options for the different style module
2452        PlatformOptions = self.EdkIIBuildOption
2453        ModuleTypeOptions = self.Platform.GetBuildOptionsByModuleType(EDKII_NAME, Module.ModuleType)
2454        ModuleTypeOptions = self._ExpandBuildOption(ModuleTypeOptions)
2455        ModuleOptions = self._ExpandBuildOption(Module.BuildOptions)
2456        if Module in self.Platform.Modules:
2457            PlatformModule = self.Platform.Modules[str(Module)]
2458            PlatformModuleOptions = self._ExpandBuildOption(PlatformModule.BuildOptions)
2459        else:
2460            PlatformModuleOptions = {}
2461
2462        BuildRuleOrder = None
2463        for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
2464            for Tool in Options:
2465                for Attr in Options[Tool]:
2466                    if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
2467                        BuildRuleOrder = Options[Tool][Attr]
2468
2469        AllTools = set(list(ModuleOptions.keys()) + list(PlatformOptions.keys()) +
2470                       list(PlatformModuleOptions.keys()) + list(ModuleTypeOptions.keys()) +
2471                       list(self.ToolDefinition.keys()))
2472        BuildOptions = defaultdict(lambda: defaultdict(str))
2473        for Tool in AllTools:
2474            for Options in [self.ToolDefinition, ModuleOptions, PlatformOptions, ModuleTypeOptions, PlatformModuleOptions]:
2475                if Tool not in Options:
2476                    continue
2477                for Attr in Options[Tool]:
2478                    #
2479                    # Do not generate it in Makefile
2480                    #
2481                    if Attr == TAB_TOD_DEFINES_BUILDRULEORDER:
2482                        continue
2483                    Value = Options[Tool][Attr]
2484                    # check if override is indicated
2485                    if Value.startswith('='):
2486                        BuildOptions[Tool][Attr] = mws.handleWsMacro(Value[1:])
2487                    else:
2488                        if Attr != 'PATH':
2489                            BuildOptions[Tool][Attr] += " " + mws.handleWsMacro(Value)
2490                        else:
2491                            BuildOptions[Tool][Attr] = mws.handleWsMacro(Value)
2492
2493        return BuildOptions, BuildRuleOrder
2494
2495#
2496# extend lists contained in a dictionary with lists stored in another dictionary
2497# if CopyToDict is not derived from DefaultDict(list) then this may raise exception
2498#
2499def ExtendCopyDictionaryLists(CopyToDict, CopyFromDict):
2500    for Key in CopyFromDict:
2501        CopyToDict[Key].extend(CopyFromDict[Key])
2502
2503# Create a directory specified by a set of path elements and return the full path
2504def _MakeDir(PathList):
2505    RetVal = path.join(*PathList)
2506    CreateDirectory(RetVal)
2507    return RetVal
2508
2509## ModuleAutoGen class
2510#
2511# This class encapsules the AutoGen behaviors for the build tools. In addition to
2512# the generation of AutoGen.h and AutoGen.c, it will generate *.depex file according
2513# to the [depex] section in module's inf file.
2514#
2515class ModuleAutoGen(AutoGen):
2516    # call super().__init__ then call the worker function with different parameter count
2517    def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
2518        if not hasattr(self, "_Init"):
2519            self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args)
2520            self._Init = True
2521
2522    ## Cache the timestamps of metafiles of every module in a class attribute
2523    #
2524    TimeDict = {}
2525
2526    def __new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
2527        # check if this module is employed by active platform
2528        if not PlatformAutoGen(Workspace, args[0], Target, Toolchain, Arch).ValidModule(MetaFile):
2529            EdkLogger.verbose("Module [%s] for [%s] is not employed by active platform\n" \
2530                              % (MetaFile, Arch))
2531            return None
2532        return super(ModuleAutoGen, cls).__new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
2533
2534    ## Initialize ModuleAutoGen
2535    #
2536    #   @param      Workspace           EdkIIWorkspaceBuild object
2537    #   @param      ModuleFile          The path of module file
2538    #   @param      Target              Build target (DEBUG, RELEASE)
2539    #   @param      Toolchain           Name of tool chain
2540    #   @param      Arch                The arch the module supports
2541    #   @param      PlatformFile        Platform meta-file
2542    #
2543    def _InitWorker(self, Workspace, ModuleFile, Target, Toolchain, Arch, PlatformFile):
2544        EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen module [%s] [%s]" % (ModuleFile, Arch))
2545        GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (ModuleFile, Arch, Toolchain, Target)
2546
2547        self.Workspace = Workspace
2548        self.WorkspaceDir = Workspace.WorkspaceDir
2549        self.MetaFile = ModuleFile
2550        self.PlatformInfo = PlatformAutoGen(Workspace, PlatformFile, Target, Toolchain, Arch)
2551
2552        self.SourceDir = self.MetaFile.SubDir
2553        self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir)
2554
2555        self.ToolChain = Toolchain
2556        self.BuildTarget = Target
2557        self.Arch = Arch
2558        self.ToolChainFamily = self.PlatformInfo.ToolChainFamily
2559        self.BuildRuleFamily = self.PlatformInfo.BuildRuleFamily
2560
2561        self.IsCodeFileCreated = False
2562        self.IsAsBuiltInfCreated = False
2563        self.DepexGenerated = False
2564
2565        self.BuildDatabase = self.Workspace.BuildDatabase
2566        self.BuildRuleOrder = None
2567        self.BuildTime      = 0
2568
2569        self._PcdComments = OrderedListDict()
2570        self._GuidComments = OrderedListDict()
2571        self._ProtocolComments = OrderedListDict()
2572        self._PpiComments = OrderedListDict()
2573        self._BuildTargets            = None
2574        self._IntroBuildTargetList    = None
2575        self._FinalBuildTargetList    = None
2576        self._FileTypes               = None
2577
2578        self.AutoGenDepSet = set()
2579        self.ReferenceModules = []
2580        self.ConstPcd                  = {}
2581
2582
2583    def __repr__(self):
2584        return "%s [%s]" % (self.MetaFile, self.Arch)
2585
2586    # Get FixedAtBuild Pcds of this Module
2587    @cached_property
2588    def FixedAtBuildPcds(self):
2589        RetVal = []
2590        for Pcd in self.ModulePcdList:
2591            if Pcd.Type != TAB_PCDS_FIXED_AT_BUILD:
2592                continue
2593            if Pcd not in RetVal:
2594                RetVal.append(Pcd)
2595        return RetVal
2596
2597    @cached_property
2598    def FixedVoidTypePcds(self):
2599        RetVal = {}
2600        for Pcd in self.FixedAtBuildPcds:
2601            if Pcd.DatumType == TAB_VOID:
2602                if '{}.{}'.format(Pcd.TokenSpaceGuidCName, Pcd.TokenCName) not in RetVal:
2603                    RetVal['{}.{}'.format(Pcd.TokenSpaceGuidCName, Pcd.TokenCName)] = Pcd.DefaultValue
2604        return RetVal
2605
2606    @property
2607    def UniqueBaseName(self):
2608        BaseName = self.Name
2609        for Module in self.PlatformInfo.ModuleAutoGenList:
2610            if Module.MetaFile == self.MetaFile:
2611                continue
2612            if Module.Name == self.Name:
2613                if uuid.UUID(Module.Guid) == uuid.UUID(self.Guid):
2614                    EdkLogger.error("build", FILE_DUPLICATED, 'Modules have same BaseName and FILE_GUID:\n'
2615                                    '  %s\n  %s' % (Module.MetaFile, self.MetaFile))
2616                BaseName = '%s_%s' % (self.Name, self.Guid)
2617        return BaseName
2618
2619    # Macros could be used in build_rule.txt (also Makefile)
2620    @cached_property
2621    def Macros(self):
2622        return OrderedDict((
2623            ("WORKSPACE" ,self.WorkspaceDir),
2624            ("MODULE_NAME" ,self.Name),
2625            ("MODULE_NAME_GUID" ,self.UniqueBaseName),
2626            ("MODULE_GUID" ,self.Guid),
2627            ("MODULE_VERSION" ,self.Version),
2628            ("MODULE_TYPE" ,self.ModuleType),
2629            ("MODULE_FILE" ,str(self.MetaFile)),
2630            ("MODULE_FILE_BASE_NAME" ,self.MetaFile.BaseName),
2631            ("MODULE_RELATIVE_DIR" ,self.SourceDir),
2632            ("MODULE_DIR" ,self.SourceDir),
2633            ("BASE_NAME" ,self.Name),
2634            ("ARCH" ,self.Arch),
2635            ("TOOLCHAIN" ,self.ToolChain),
2636            ("TOOLCHAIN_TAG" ,self.ToolChain),
2637            ("TOOL_CHAIN_TAG" ,self.ToolChain),
2638            ("TARGET" ,self.BuildTarget),
2639            ("BUILD_DIR" ,self.PlatformInfo.BuildDir),
2640            ("BIN_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
2641            ("LIB_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
2642            ("MODULE_BUILD_DIR" ,self.BuildDir),
2643            ("OUTPUT_DIR" ,self.OutputDir),
2644            ("DEBUG_DIR" ,self.DebugDir),
2645            ("DEST_DIR_OUTPUT" ,self.OutputDir),
2646            ("DEST_DIR_DEBUG" ,self.DebugDir),
2647            ("PLATFORM_NAME" ,self.PlatformInfo.Name),
2648            ("PLATFORM_GUID" ,self.PlatformInfo.Guid),
2649            ("PLATFORM_VERSION" ,self.PlatformInfo.Version),
2650            ("PLATFORM_RELATIVE_DIR" ,self.PlatformInfo.SourceDir),
2651            ("PLATFORM_DIR" ,mws.join(self.WorkspaceDir, self.PlatformInfo.SourceDir)),
2652            ("PLATFORM_OUTPUT_DIR" ,self.PlatformInfo.OutputDir),
2653            ("FFS_OUTPUT_DIR" ,self.FfsOutputDir)
2654            ))
2655
2656    ## Return the module build data object
2657    @cached_property
2658    def Module(self):
2659        return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
2660
2661    ## Return the module name
2662    @cached_property
2663    def Name(self):
2664        return self.Module.BaseName
2665
2666    ## Return the module DxsFile if exist
2667    @cached_property
2668    def DxsFile(self):
2669        return self.Module.DxsFile
2670
2671    ## Return the module meta-file GUID
2672    @cached_property
2673    def Guid(self):
2674        #
2675        # To build same module more than once, the module path with FILE_GUID overridden has
2676        # the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
2677        # in DSC. The overridden GUID can be retrieved from file name
2678        #
2679        if os.path.basename(self.MetaFile.File) != os.path.basename(self.MetaFile.Path):
2680            #
2681            # Length of GUID is 36
2682            #
2683            return os.path.basename(self.MetaFile.Path)[:36]
2684        return self.Module.Guid
2685
2686    ## Return the module version
2687    @cached_property
2688    def Version(self):
2689        return self.Module.Version
2690
2691    ## Return the module type
2692    @cached_property
2693    def ModuleType(self):
2694        return self.Module.ModuleType
2695
2696    ## Return the component type (for Edk.x style of module)
2697    @cached_property
2698    def ComponentType(self):
2699        return self.Module.ComponentType
2700
2701    ## Return the build type
2702    @cached_property
2703    def BuildType(self):
2704        return self.Module.BuildType
2705
2706    ## Return the PCD_IS_DRIVER setting
2707    @cached_property
2708    def PcdIsDriver(self):
2709        return self.Module.PcdIsDriver
2710
2711    ## Return the autogen version, i.e. module meta-file version
2712    @cached_property
2713    def AutoGenVersion(self):
2714        return self.Module.AutoGenVersion
2715
2716    ## Check if the module is library or not
2717    @cached_property
2718    def IsLibrary(self):
2719        return bool(self.Module.LibraryClass)
2720
2721    ## Check if the module is binary module or not
2722    @cached_property
2723    def IsBinaryModule(self):
2724        return self.Module.IsBinaryModule
2725
2726    ## Return the directory to store intermediate files of the module
2727    @cached_property
2728    def BuildDir(self):
2729        return _MakeDir((
2730                                    self.PlatformInfo.BuildDir,
2731                                    self.Arch,
2732                                    self.SourceDir,
2733                                    self.MetaFile.BaseName
2734            ))
2735
2736    ## Return the directory to store the intermediate object files of the module
2737    @cached_property
2738    def OutputDir(self):
2739        return _MakeDir((self.BuildDir, "OUTPUT"))
2740
2741    ## Return the directory path to store ffs file
2742    @cached_property
2743    def FfsOutputDir(self):
2744        if GlobalData.gFdfParser:
2745            return path.join(self.PlatformInfo.BuildDir, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name)
2746        return ''
2747
2748    ## Return the directory to store auto-gened source files of the module
2749    @cached_property
2750    def DebugDir(self):
2751        return _MakeDir((self.BuildDir, "DEBUG"))
2752
2753    ## Return the path of custom file
2754    @cached_property
2755    def CustomMakefile(self):
2756        RetVal = {}
2757        for Type in self.Module.CustomMakefile:
2758            MakeType = gMakeTypeMap[Type] if Type in gMakeTypeMap else 'nmake'
2759            File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type])
2760            RetVal[MakeType] = File
2761        return RetVal
2762
2763    ## Return the directory of the makefile
2764    #
2765    #   @retval     string  The directory string of module's makefile
2766    #
2767    @cached_property
2768    def MakeFileDir(self):
2769        return self.BuildDir
2770
2771    ## Return build command string
2772    #
2773    #   @retval     string  Build command string
2774    #
2775    @cached_property
2776    def BuildCommand(self):
2777        return self.PlatformInfo.BuildCommand
2778
2779    ## Get object list of all packages the module and its dependent libraries belong to
2780    #
2781    #   @retval     list    The list of package object
2782    #
2783    @cached_property
2784    def DerivedPackageList(self):
2785        PackageList = []
2786        for M in [self.Module] + self.DependentLibraryList:
2787            for Package in M.Packages:
2788                if Package in PackageList:
2789                    continue
2790                PackageList.append(Package)
2791        return PackageList
2792
2793    ## Get the depex string
2794    #
2795    # @return : a string contain all depex expression.
2796    def _GetDepexExpresionString(self):
2797        DepexStr = ''
2798        DepexList = []
2799        ## DPX_SOURCE IN Define section.
2800        if self.Module.DxsFile:
2801            return DepexStr
2802        for M in [self.Module] + self.DependentLibraryList:
2803            Filename = M.MetaFile.Path
2804            InfObj = InfSectionParser.InfSectionParser(Filename)
2805            DepexExpressionList = InfObj.GetDepexExpresionList()
2806            for DepexExpression in DepexExpressionList:
2807                for key in DepexExpression:
2808                    Arch, ModuleType = key
2809                    DepexExpr = [x for x in DepexExpression[key] if not str(x).startswith('#')]
2810                    # the type of build module is USER_DEFINED.
2811                    # All different DEPEX section tags would be copied into the As Built INF file
2812                    # and there would be separate DEPEX section tags
2813                    if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED:
2814                        if (Arch.upper() == self.Arch.upper()) and (ModuleType.upper() != TAB_ARCH_COMMON):
2815                            DepexList.append({(Arch, ModuleType): DepexExpr})
2816                    else:
2817                        if Arch.upper() == TAB_ARCH_COMMON or \
2818                          (Arch.upper() == self.Arch.upper() and \
2819                          ModuleType.upper() in [TAB_ARCH_COMMON, self.ModuleType.upper()]):
2820                            DepexList.append({(Arch, ModuleType): DepexExpr})
2821
2822        #the type of build module is USER_DEFINED.
2823        if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED:
2824            for Depex in DepexList:
2825                for key in Depex:
2826                    DepexStr += '[Depex.%s.%s]\n' % key
2827                    DepexStr += '\n'.join('# '+ val for val in Depex[key])
2828                    DepexStr += '\n\n'
2829            if not DepexStr:
2830                return '[Depex.%s]\n' % self.Arch
2831            return DepexStr
2832
2833        #the type of build module not is USER_DEFINED.
2834        Count = 0
2835        for Depex in DepexList:
2836            Count += 1
2837            if DepexStr != '':
2838                DepexStr += ' AND '
2839            DepexStr += '('
2840            for D in Depex.values():
2841                DepexStr += ' '.join(val for val in D)
2842            Index = DepexStr.find('END')
2843            if Index > -1 and Index == len(DepexStr) - 3:
2844                DepexStr = DepexStr[:-3]
2845            DepexStr = DepexStr.strip()
2846            DepexStr += ')'
2847        if Count == 1:
2848            DepexStr = DepexStr.lstrip('(').rstrip(')').strip()
2849        if not DepexStr:
2850            return '[Depex.%s]\n' % self.Arch
2851        return '[Depex.%s]\n#  ' % self.Arch + DepexStr
2852
2853    ## Merge dependency expression
2854    #
2855    #   @retval     list    The token list of the dependency expression after parsed
2856    #
2857    @cached_property
2858    def DepexList(self):
2859        if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
2860            return {}
2861
2862        DepexList = []
2863        #
2864        # Append depex from dependent libraries, if not "BEFORE", "AFTER" expression
2865        #
2866        for M in [self.Module] + self.DependentLibraryList:
2867            Inherited = False
2868            for D in M.Depex[self.Arch, self.ModuleType]:
2869                if DepexList != []:
2870                    DepexList.append('AND')
2871                DepexList.append('(')
2872                #replace D with value if D is FixedAtBuild PCD
2873                NewList = []
2874                for item in D:
2875                    if '.' not in item:
2876                        NewList.append(item)
2877                    else:
2878                        FixedVoidTypePcds = {}
2879                        if item in self.FixedVoidTypePcds:
2880                            FixedVoidTypePcds = self.FixedVoidTypePcds
2881                        elif M in self.PlatformInfo.LibraryAutoGenList:
2882                            Index = self.PlatformInfo.LibraryAutoGenList.index(M)
2883                            FixedVoidTypePcds = self.PlatformInfo.LibraryAutoGenList[Index].FixedVoidTypePcds
2884                        if item not in FixedVoidTypePcds:
2885                            EdkLogger.error("build", FORMAT_INVALID, "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type in the module.".format(item))
2886                        else:
2887                            Value = FixedVoidTypePcds[item]
2888                            if len(Value.split(',')) != 16:
2889                                EdkLogger.error("build", FORMAT_INVALID,
2890                                                "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type and 16 bytes in the module.".format(item))
2891                            NewList.append(Value)
2892                DepexList.extend(NewList)
2893                if DepexList[-1] == 'END':  # no need of a END at this time
2894                    DepexList.pop()
2895                DepexList.append(')')
2896                Inherited = True
2897            if Inherited:
2898                EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexList))
2899            if 'BEFORE' in DepexList or 'AFTER' in DepexList:
2900                break
2901            if len(DepexList) > 0:
2902                EdkLogger.verbose('')
2903        return {self.ModuleType:DepexList}
2904
2905    ## Merge dependency expression
2906    #
2907    #   @retval     list    The token list of the dependency expression after parsed
2908    #
2909    @cached_property
2910    def DepexExpressionDict(self):
2911        if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
2912            return {}
2913
2914        DepexExpressionString = ''
2915        #
2916        # Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion
2917        #
2918        for M in [self.Module] + self.DependentLibraryList:
2919            Inherited = False
2920            for D in M.DepexExpression[self.Arch, self.ModuleType]:
2921                if DepexExpressionString != '':
2922                    DepexExpressionString += ' AND '
2923                DepexExpressionString += '('
2924                DepexExpressionString += D
2925                DepexExpressionString = DepexExpressionString.rstrip('END').strip()
2926                DepexExpressionString += ')'
2927                Inherited = True
2928            if Inherited:
2929                EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexExpressionString))
2930            if 'BEFORE' in DepexExpressionString or 'AFTER' in DepexExpressionString:
2931                break
2932        if len(DepexExpressionString) > 0:
2933            EdkLogger.verbose('')
2934
2935        return {self.ModuleType:DepexExpressionString}
2936
2937    # Get the tiano core user extension, it is contain dependent library.
2938    # @retval: a list contain tiano core userextension.
2939    #
2940    def _GetTianoCoreUserExtensionList(self):
2941        TianoCoreUserExtentionList = []
2942        for M in [self.Module] + self.DependentLibraryList:
2943            Filename = M.MetaFile.Path
2944            InfObj = InfSectionParser.InfSectionParser(Filename)
2945            TianoCoreUserExtenList = InfObj.GetUserExtensionTianoCore()
2946            for TianoCoreUserExtent in TianoCoreUserExtenList:
2947                for Section in TianoCoreUserExtent:
2948                    ItemList = Section.split(TAB_SPLIT)
2949                    Arch = self.Arch
2950                    if len(ItemList) == 4:
2951                        Arch = ItemList[3]
2952                    if Arch.upper() == TAB_ARCH_COMMON or Arch.upper() == self.Arch.upper():
2953                        TianoCoreList = []
2954                        TianoCoreList.extend([TAB_SECTION_START + Section + TAB_SECTION_END])
2955                        TianoCoreList.extend(TianoCoreUserExtent[Section][:])
2956                        TianoCoreList.append('\n')
2957                        TianoCoreUserExtentionList.append(TianoCoreList)
2958
2959        return TianoCoreUserExtentionList
2960
2961    ## Return the list of specification version required for the module
2962    #
2963    #   @retval     list    The list of specification defined in module file
2964    #
2965    @cached_property
2966    def Specification(self):
2967        return self.Module.Specification
2968
2969    ## Tool option for the module build
2970    #
2971    #   @param      PlatformInfo    The object of PlatformBuildInfo
2972    #   @retval     dict            The dict containing valid options
2973    #
2974    @cached_property
2975    def BuildOption(self):
2976        RetVal, self.BuildRuleOrder = self.PlatformInfo.ApplyBuildOption(self.Module)
2977        if self.BuildRuleOrder:
2978            self.BuildRuleOrder = ['.%s' % Ext for Ext in self.BuildRuleOrder.split()]
2979        return RetVal
2980
2981    ## Get include path list from tool option for the module build
2982    #
2983    #   @retval     list            The include path list
2984    #
2985    @cached_property
2986    def BuildOptionIncPathList(self):
2987        #
2988        # Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
2989        # is the former use /I , the Latter used -I to specify include directories
2990        #
2991        if self.PlatformInfo.ToolChainFamily in (TAB_COMPILER_MSFT):
2992            BuildOptIncludeRegEx = gBuildOptIncludePatternMsft
2993        elif self.PlatformInfo.ToolChainFamily in ('INTEL', 'GCC', 'RVCT'):
2994            BuildOptIncludeRegEx = gBuildOptIncludePatternOther
2995        else:
2996            #
2997            # New ToolChainFamily, don't known whether there is option to specify include directories
2998            #
2999            return []
3000
3001        RetVal = []
3002        for Tool in ('CC', 'PP', 'VFRPP', 'ASLPP', 'ASLCC', 'APP', 'ASM'):
3003            try:
3004                FlagOption = self.BuildOption[Tool]['FLAGS']
3005            except KeyError:
3006                FlagOption = ''
3007
3008            if self.ToolChainFamily != 'RVCT':
3009                IncPathList = [NormPath(Path, self.Macros) for Path in BuildOptIncludeRegEx.findall(FlagOption)]
3010            else:
3011                #
3012                # RVCT may specify a list of directory seperated by commas
3013                #
3014                IncPathList = []
3015                for Path in BuildOptIncludeRegEx.findall(FlagOption):
3016                    PathList = GetSplitList(Path, TAB_COMMA_SPLIT)
3017                    IncPathList.extend(NormPath(PathEntry, self.Macros) for PathEntry in PathList)
3018
3019            #
3020            # EDK II modules must not reference header files outside of the packages they depend on or
3021            # within the module's directory tree. Report error if violation.
3022            #
3023            if GlobalData.gDisableIncludePathCheck == False:
3024                for Path in IncPathList:
3025                    if (Path not in self.IncludePathList) and (CommonPath([Path, self.MetaFile.Dir]) != self.MetaFile.Dir):
3026                        ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption)
3027                        EdkLogger.error("build",
3028                                        PARAMETER_INVALID,
3029                                        ExtraData=ErrMsg,
3030                                        File=str(self.MetaFile))
3031            RetVal += IncPathList
3032        return RetVal
3033
3034    ## Return a list of files which can be built from source
3035    #
3036    #  What kind of files can be built is determined by build rules in
3037    #  $(CONF_DIRECTORY)/build_rule.txt and toolchain family.
3038    #
3039    @cached_property
3040    def SourceFileList(self):
3041        RetVal = []
3042        ToolChainTagSet = {"", TAB_STAR, self.ToolChain}
3043        ToolChainFamilySet = {"", TAB_STAR, self.ToolChainFamily, self.BuildRuleFamily}
3044        for F in self.Module.Sources:
3045            # match tool chain
3046            if F.TagName not in ToolChainTagSet:
3047                EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, "
3048                                "but [%s] is currently used" % (F.TagName, str(F), self.ToolChain))
3049                continue
3050            # match tool chain family or build rule family
3051            if F.ToolChainFamily not in ToolChainFamilySet:
3052                EdkLogger.debug(
3053                            EdkLogger.DEBUG_0,
3054                            "The file [%s] must be built by tools of [%s], " \
3055                            "but current toolchain family is [%s], buildrule family is [%s]" \
3056                                % (str(F), F.ToolChainFamily, self.ToolChainFamily, self.BuildRuleFamily))
3057                continue
3058
3059            # add the file path into search path list for file including
3060            if F.Dir not in self.IncludePathList:
3061                self.IncludePathList.insert(0, F.Dir)
3062            RetVal.append(F)
3063
3064        self._MatchBuildRuleOrder(RetVal)
3065
3066        for F in RetVal:
3067            self._ApplyBuildRule(F, TAB_UNKNOWN_FILE)
3068        return RetVal
3069
3070    def _MatchBuildRuleOrder(self, FileList):
3071        Order_Dict = {}
3072        self.BuildOption
3073        for SingleFile in FileList:
3074            if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder and SingleFile.Ext in self.BuildRules:
3075                key = SingleFile.Path.rsplit(SingleFile.Ext,1)[0]
3076                if key in Order_Dict:
3077                    Order_Dict[key].append(SingleFile.Ext)
3078                else:
3079                    Order_Dict[key] = [SingleFile.Ext]
3080
3081        RemoveList = []
3082        for F in Order_Dict:
3083            if len(Order_Dict[F]) > 1:
3084                Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i))
3085                for Ext in Order_Dict[F][1:]:
3086                    RemoveList.append(F + Ext)
3087
3088        for item in RemoveList:
3089            FileList.remove(item)
3090
3091        return FileList
3092
3093    ## Return the list of unicode files
3094    @cached_property
3095    def UnicodeFileList(self):
3096        return self.FileTypes.get(TAB_UNICODE_FILE,[])
3097
3098    ## Return the list of vfr files
3099    @cached_property
3100    def VfrFileList(self):
3101        return self.FileTypes.get(TAB_VFR_FILE, [])
3102
3103    ## Return the list of Image Definition files
3104    @cached_property
3105    def IdfFileList(self):
3106        return self.FileTypes.get(TAB_IMAGE_FILE,[])
3107
3108    ## Return a list of files which can be built from binary
3109    #
3110    #  "Build" binary files are just to copy them to build directory.
3111    #
3112    #   @retval     list            The list of files which can be built later
3113    #
3114    @cached_property
3115    def BinaryFileList(self):
3116        RetVal = []
3117        for F in self.Module.Binaries:
3118            if F.Target not in [TAB_ARCH_COMMON, TAB_STAR] and F.Target != self.BuildTarget:
3119                continue
3120            RetVal.append(F)
3121            self._ApplyBuildRule(F, F.Type, BinaryFileList=RetVal)
3122        return RetVal
3123
3124    @cached_property
3125    def BuildRules(self):
3126        RetVal = {}
3127        BuildRuleDatabase = self.PlatformInfo.BuildRule
3128        for Type in BuildRuleDatabase.FileTypeList:
3129            #first try getting build rule by BuildRuleFamily
3130            RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.BuildRuleFamily]
3131            if not RuleObject:
3132                # build type is always module type, but ...
3133                if self.ModuleType != self.BuildType:
3134                    RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.BuildRuleFamily]
3135            #second try getting build rule by ToolChainFamily
3136            if not RuleObject:
3137                RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.ToolChainFamily]
3138                if not RuleObject:
3139                    # build type is always module type, but ...
3140                    if self.ModuleType != self.BuildType:
3141                        RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.ToolChainFamily]
3142            if not RuleObject:
3143                continue
3144            RuleObject = RuleObject.Instantiate(self.Macros)
3145            RetVal[Type] = RuleObject
3146            for Ext in RuleObject.SourceFileExtList:
3147                RetVal[Ext] = RuleObject
3148        return RetVal
3149
3150    def _ApplyBuildRule(self, File, FileType, BinaryFileList=None):
3151        if self._BuildTargets is None:
3152            self._IntroBuildTargetList = set()
3153            self._FinalBuildTargetList = set()
3154            self._BuildTargets = defaultdict(set)
3155            self._FileTypes = defaultdict(set)
3156
3157        if not BinaryFileList:
3158            BinaryFileList = self.BinaryFileList
3159
3160        SubDirectory = os.path.join(self.OutputDir, File.SubDir)
3161        if not os.path.exists(SubDirectory):
3162            CreateDirectory(SubDirectory)
3163        LastTarget = None
3164        RuleChain = set()
3165        SourceList = [File]
3166        Index = 0
3167        #
3168        # Make sure to get build rule order value
3169        #
3170        self.BuildOption
3171
3172        while Index < len(SourceList):
3173            Source = SourceList[Index]
3174            Index = Index + 1
3175
3176            if Source != File:
3177                CreateDirectory(Source.Dir)
3178
3179            if File.IsBinary and File == Source and File in BinaryFileList:
3180                # Skip all files that are not binary libraries
3181                if not self.IsLibrary:
3182                    continue
3183                RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE]
3184            elif FileType in self.BuildRules:
3185                RuleObject = self.BuildRules[FileType]
3186            elif Source.Ext in self.BuildRules:
3187                RuleObject = self.BuildRules[Source.Ext]
3188            else:
3189                # stop at no more rules
3190                if LastTarget:
3191                    self._FinalBuildTargetList.add(LastTarget)
3192                break
3193
3194            FileType = RuleObject.SourceFileType
3195            self._FileTypes[FileType].add(Source)
3196
3197            # stop at STATIC_LIBRARY for library
3198            if self.IsLibrary and FileType == TAB_STATIC_LIBRARY:
3199                if LastTarget:
3200                    self._FinalBuildTargetList.add(LastTarget)
3201                break
3202
3203            Target = RuleObject.Apply(Source, self.BuildRuleOrder)
3204            if not Target:
3205                if LastTarget:
3206                    self._FinalBuildTargetList.add(LastTarget)
3207                break
3208            elif not Target.Outputs:
3209                # Only do build for target with outputs
3210                self._FinalBuildTargetList.add(Target)
3211
3212            self._BuildTargets[FileType].add(Target)
3213
3214            if not Source.IsBinary and Source == File:
3215                self._IntroBuildTargetList.add(Target)
3216
3217            # to avoid cyclic rule
3218            if FileType in RuleChain:
3219                break
3220
3221            RuleChain.add(FileType)
3222            SourceList.extend(Target.Outputs)
3223            LastTarget = Target
3224            FileType = TAB_UNKNOWN_FILE
3225
3226    @cached_property
3227    def Targets(self):
3228        if self._BuildTargets is None:
3229            self._IntroBuildTargetList = set()
3230            self._FinalBuildTargetList = set()
3231            self._BuildTargets = defaultdict(set)
3232            self._FileTypes = defaultdict(set)
3233
3234        #TRICK: call SourceFileList property to apply build rule for source files
3235        self.SourceFileList
3236
3237        #TRICK: call _GetBinaryFileList to apply build rule for binary files
3238        self.BinaryFileList
3239
3240        return self._BuildTargets
3241
3242    @cached_property
3243    def IntroTargetList(self):
3244        self.Targets
3245        return self._IntroBuildTargetList
3246
3247    @cached_property
3248    def CodaTargetList(self):
3249        self.Targets
3250        return self._FinalBuildTargetList
3251
3252    @cached_property
3253    def FileTypes(self):
3254        self.Targets
3255        return self._FileTypes
3256
3257    ## Get the list of package object the module depends on
3258    #
3259    #   @retval     list    The package object list
3260    #
3261    @cached_property
3262    def DependentPackageList(self):
3263        return self.Module.Packages
3264
3265    ## Return the list of auto-generated code file
3266    #
3267    #   @retval     list        The list of auto-generated file
3268    #
3269    @cached_property
3270    def AutoGenFileList(self):
3271        AutoGenUniIdf = self.BuildType != 'UEFI_HII'
3272        UniStringBinBuffer = BytesIO()
3273        IdfGenBinBuffer = BytesIO()
3274        RetVal = {}
3275        AutoGenC = TemplateString()
3276        AutoGenH = TemplateString()
3277        StringH = TemplateString()
3278        StringIdf = TemplateString()
3279        GenC.CreateCode(self, AutoGenC, AutoGenH, StringH, AutoGenUniIdf, UniStringBinBuffer, StringIdf, AutoGenUniIdf, IdfGenBinBuffer)
3280        #
3281        # AutoGen.c is generated if there are library classes in inf, or there are object files
3282        #
3283        if str(AutoGenC) != "" and (len(self.Module.LibraryClasses) > 0
3284                                    or TAB_OBJECT_FILE in self.FileTypes):
3285            AutoFile = PathClass(gAutoGenCodeFileName, self.DebugDir)
3286            RetVal[AutoFile] = str(AutoGenC)
3287            self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3288        if str(AutoGenH) != "":
3289            AutoFile = PathClass(gAutoGenHeaderFileName, self.DebugDir)
3290            RetVal[AutoFile] = str(AutoGenH)
3291            self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3292        if str(StringH) != "":
3293            AutoFile = PathClass(gAutoGenStringFileName % {"module_name":self.Name}, self.DebugDir)
3294            RetVal[AutoFile] = str(StringH)
3295            self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3296        if UniStringBinBuffer is not None and UniStringBinBuffer.getvalue() != b"":
3297            AutoFile = PathClass(gAutoGenStringFormFileName % {"module_name":self.Name}, self.OutputDir)
3298            RetVal[AutoFile] = UniStringBinBuffer.getvalue()
3299            AutoFile.IsBinary = True
3300            self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3301        if UniStringBinBuffer is not None:
3302            UniStringBinBuffer.close()
3303        if str(StringIdf) != "":
3304            AutoFile = PathClass(gAutoGenImageDefFileName % {"module_name":self.Name}, self.DebugDir)
3305            RetVal[AutoFile] = str(StringIdf)
3306            self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3307        if IdfGenBinBuffer is not None and IdfGenBinBuffer.getvalue() != b"":
3308            AutoFile = PathClass(gAutoGenIdfFileName % {"module_name":self.Name}, self.OutputDir)
3309            RetVal[AutoFile] = IdfGenBinBuffer.getvalue()
3310            AutoFile.IsBinary = True
3311            self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
3312        if IdfGenBinBuffer is not None:
3313            IdfGenBinBuffer.close()
3314        return RetVal
3315
3316    ## Return the list of library modules explicitly or implicitly used by this module
3317    @cached_property
3318    def DependentLibraryList(self):
3319        # only merge library classes and PCD for non-library module
3320        if self.IsLibrary:
3321            return []
3322        return self.PlatformInfo.ApplyLibraryInstance(self.Module)
3323
3324    ## Get the list of PCDs from current module
3325    #
3326    #   @retval     list                    The list of PCD
3327    #
3328    @cached_property
3329    def ModulePcdList(self):
3330        # apply PCD settings from platform
3331        RetVal = self.PlatformInfo.ApplyPcdSetting(self.Module, self.Module.Pcds)
3332        ExtendCopyDictionaryLists(self._PcdComments, self.Module.PcdComments)
3333        return RetVal
3334
3335    ## Get the list of PCDs from dependent libraries
3336    #
3337    #   @retval     list                    The list of PCD
3338    #
3339    @cached_property
3340    def LibraryPcdList(self):
3341        if self.IsLibrary:
3342            return []
3343        RetVal = []
3344        Pcds = set()
3345        # get PCDs from dependent libraries
3346        for Library in self.DependentLibraryList:
3347            PcdsInLibrary = OrderedDict()
3348            ExtendCopyDictionaryLists(self._PcdComments, Library.PcdComments)
3349            for Key in Library.Pcds:
3350                # skip duplicated PCDs
3351                if Key in self.Module.Pcds or Key in Pcds:
3352                    continue
3353                Pcds.add(Key)
3354                PcdsInLibrary[Key] = copy.copy(Library.Pcds[Key])
3355            RetVal.extend(self.PlatformInfo.ApplyPcdSetting(self.Module, PcdsInLibrary, Library=Library))
3356        return RetVal
3357
3358    ## Get the GUID value mapping
3359    #
3360    #   @retval     dict    The mapping between GUID cname and its value
3361    #
3362    @cached_property
3363    def GuidList(self):
3364        RetVal = OrderedDict(self.Module.Guids)
3365        for Library in self.DependentLibraryList:
3366            RetVal.update(Library.Guids)
3367            ExtendCopyDictionaryLists(self._GuidComments, Library.GuidComments)
3368        ExtendCopyDictionaryLists(self._GuidComments, self.Module.GuidComments)
3369        return RetVal
3370
3371    @cached_property
3372    def GetGuidsUsedByPcd(self):
3373        RetVal = OrderedDict(self.Module.GetGuidsUsedByPcd())
3374        for Library in self.DependentLibraryList:
3375            RetVal.update(Library.GetGuidsUsedByPcd())
3376        return RetVal
3377    ## Get the protocol value mapping
3378    #
3379    #   @retval     dict    The mapping between protocol cname and its value
3380    #
3381    @cached_property
3382    def ProtocolList(self):
3383        RetVal = OrderedDict(self.Module.Protocols)
3384        for Library in self.DependentLibraryList:
3385            RetVal.update(Library.Protocols)
3386            ExtendCopyDictionaryLists(self._ProtocolComments, Library.ProtocolComments)
3387        ExtendCopyDictionaryLists(self._ProtocolComments, self.Module.ProtocolComments)
3388        return RetVal
3389
3390    ## Get the PPI value mapping
3391    #
3392    #   @retval     dict    The mapping between PPI cname and its value
3393    #
3394    @cached_property
3395    def PpiList(self):
3396        RetVal = OrderedDict(self.Module.Ppis)
3397        for Library in self.DependentLibraryList:
3398            RetVal.update(Library.Ppis)
3399            ExtendCopyDictionaryLists(self._PpiComments, Library.PpiComments)
3400        ExtendCopyDictionaryLists(self._PpiComments, self.Module.PpiComments)
3401        return RetVal
3402
3403    ## Get the list of include search path
3404    #
3405    #   @retval     list                    The list path
3406    #
3407    @cached_property
3408    def IncludePathList(self):
3409        RetVal = []
3410        RetVal.append(self.MetaFile.Dir)
3411        RetVal.append(self.DebugDir)
3412
3413        for Package in self.Module.Packages:
3414            PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)
3415            if PackageDir not in RetVal:
3416                RetVal.append(PackageDir)
3417            IncludesList = Package.Includes
3418            if Package._PrivateIncludes:
3419                if not self.MetaFile.OriginalPath.Path.startswith(PackageDir):
3420                    IncludesList = list(set(Package.Includes).difference(set(Package._PrivateIncludes)))
3421            for Inc in IncludesList:
3422                if Inc not in RetVal:
3423                    RetVal.append(str(Inc))
3424        return RetVal
3425
3426    @cached_property
3427    def IncludePathLength(self):
3428        return sum(len(inc)+1 for inc in self.IncludePathList)
3429
3430    ## Get HII EX PCDs which maybe used by VFR
3431    #
3432    #  efivarstore used by VFR may relate with HII EX PCDs
3433    #  Get the variable name and GUID from efivarstore and HII EX PCD
3434    #  List the HII EX PCDs in As Built INF if both name and GUID match.
3435    #
3436    #  @retval    list    HII EX PCDs
3437    #
3438    def _GetPcdsMaybeUsedByVfr(self):
3439        if not self.SourceFileList:
3440            return []
3441
3442        NameGuids = set()
3443        for SrcFile in self.SourceFileList:
3444            if SrcFile.Ext.lower() != '.vfr':
3445                continue
3446            Vfri = os.path.join(self.OutputDir, SrcFile.BaseName + '.i')
3447            if not os.path.exists(Vfri):
3448                continue
3449            VfriFile = open(Vfri, 'r')
3450            Content = VfriFile.read()
3451            VfriFile.close()
3452            Pos = Content.find('efivarstore')
3453            while Pos != -1:
3454                #
3455                # Make sure 'efivarstore' is the start of efivarstore statement
3456                # In case of the value of 'name' (name = efivarstore) is equal to 'efivarstore'
3457                #
3458                Index = Pos - 1
3459                while Index >= 0 and Content[Index] in ' \t\r\n':
3460                    Index -= 1
3461                if Index >= 0 and Content[Index] != ';':
3462                    Pos = Content.find('efivarstore', Pos + len('efivarstore'))
3463                    continue
3464                #
3465                # 'efivarstore' must be followed by name and guid
3466                #
3467                Name = gEfiVarStoreNamePattern.search(Content, Pos)
3468                if not Name:
3469                    break
3470                Guid = gEfiVarStoreGuidPattern.search(Content, Pos)
3471                if not Guid:
3472                    break
3473                NameArray = _ConvertStringToByteArray('L"' + Name.group(1) + '"')
3474                NameGuids.add((NameArray, GuidStructureStringToGuidString(Guid.group(1))))
3475                Pos = Content.find('efivarstore', Name.end())
3476        if not NameGuids:
3477            return []
3478        HiiExPcds = []
3479        for Pcd in self.PlatformInfo.Platform.Pcds.values():
3480            if Pcd.Type != TAB_PCDS_DYNAMIC_EX_HII:
3481                continue
3482            for SkuInfo in Pcd.SkuInfoList.values():
3483                Value = GuidValue(SkuInfo.VariableGuid, self.PlatformInfo.PackageList, self.MetaFile.Path)
3484                if not Value:
3485                    continue
3486                Name = _ConvertStringToByteArray(SkuInfo.VariableName)
3487                Guid = GuidStructureStringToGuidString(Value)
3488                if (Name, Guid) in NameGuids and Pcd not in HiiExPcds:
3489                    HiiExPcds.append(Pcd)
3490                    break
3491
3492        return HiiExPcds
3493
3494    def _GenOffsetBin(self):
3495        VfrUniBaseName = {}
3496        for SourceFile in self.Module.Sources:
3497            if SourceFile.Type.upper() == ".VFR" :
3498                #
3499                # search the .map file to find the offset of vfr binary in the PE32+/TE file.
3500                #
3501                VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin")
3502            elif SourceFile.Type.upper() == ".UNI" :
3503                #
3504                # search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
3505                #
3506                VfrUniBaseName["UniOffsetName"] = (self.Name + "Strings")
3507
3508        if not VfrUniBaseName:
3509            return None
3510        MapFileName = os.path.join(self.OutputDir, self.Name + ".map")
3511        EfiFileName = os.path.join(self.OutputDir, self.Name + ".efi")
3512        VfrUniOffsetList = GetVariableOffset(MapFileName, EfiFileName, list(VfrUniBaseName.values()))
3513        if not VfrUniOffsetList:
3514            return None
3515
3516        OutputName = '%sOffset.bin' % self.Name
3517        UniVfrOffsetFileName    =  os.path.join( self.OutputDir, OutputName)
3518
3519        try:
3520            fInputfile = open(UniVfrOffsetFileName, "wb+", 0)
3521        except:
3522            EdkLogger.error("build", FILE_OPEN_FAILURE, "File open failed for %s" % UniVfrOffsetFileName, None)
3523
3524        # Use a instance of BytesIO to cache data
3525        fStringIO = BytesIO()
3526
3527        for Item in VfrUniOffsetList:
3528            if (Item[0].find("Strings") != -1):
3529                #
3530                # UNI offset in image.
3531                # GUID + Offset
3532                # { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
3533                #
3534                UniGuid = b'\xe0\xc5\x13\x89\xf63\x86M\x9b\xf1C\xef\x89\xfc\x06f'
3535                fStringIO.write(UniGuid)
3536                UniValue = pack ('Q', int (Item[1], 16))
3537                fStringIO.write (UniValue)
3538            else:
3539                #
3540                # VFR binary offset in image.
3541                # GUID + Offset
3542                # { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
3543                #
3544                VfrGuid = b'\xb4|\xbc\xd0Gj_I\xaa\x11q\x07F\xda\x06\xa2'
3545                fStringIO.write(VfrGuid)
3546                VfrValue = pack ('Q', int (Item[1], 16))
3547                fStringIO.write (VfrValue)
3548        #
3549        # write data into file.
3550        #
3551        try :
3552            fInputfile.write (fStringIO.getvalue())
3553        except:
3554            EdkLogger.error("build", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the "
3555                            "file been locked or using by other applications." %UniVfrOffsetFileName, None)
3556
3557        fStringIO.close ()
3558        fInputfile.close ()
3559        return OutputName
3560
3561    ## Create AsBuilt INF file the module
3562    #
3563    def CreateAsBuiltInf(self, IsOnlyCopy = False):
3564        self.OutputFile = set()
3565        if IsOnlyCopy and GlobalData.gBinCacheDest:
3566            self.CopyModuleToCache()
3567            return
3568
3569        if self.IsAsBuiltInfCreated:
3570            return
3571
3572        # Skip the following code for libraries
3573        if self.IsLibrary:
3574            return
3575
3576        # Skip the following code for modules with no source files
3577        if not self.SourceFileList:
3578            return
3579
3580        # Skip the following code for modules without any binary files
3581        if self.BinaryFileList:
3582            return
3583
3584        ### TODO: How to handles mixed source and binary modules
3585
3586        # Find all DynamicEx and PatchableInModule PCDs used by this module and dependent libraries
3587        # Also find all packages that the DynamicEx PCDs depend on
3588        Pcds = []
3589        PatchablePcds = []
3590        Packages = []
3591        PcdCheckList = []
3592        PcdTokenSpaceList = []
3593        for Pcd in self.ModulePcdList + self.LibraryPcdList:
3594            if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE:
3595                PatchablePcds.append(Pcd)
3596                PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_PATCHABLE_IN_MODULE))
3597            elif Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
3598                if Pcd not in Pcds:
3599                    Pcds.append(Pcd)
3600                    PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX))
3601                    PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC))
3602                    PcdTokenSpaceList.append(Pcd.TokenSpaceGuidCName)
3603        GuidList = OrderedDict(self.GuidList)
3604        for TokenSpace in self.GetGuidsUsedByPcd:
3605            # If token space is not referred by patch PCD or Ex PCD, remove the GUID from GUID list
3606            # The GUIDs in GUIDs section should really be the GUIDs in source INF or referred by Ex an patch PCDs
3607            if TokenSpace not in PcdTokenSpaceList and TokenSpace in GuidList:
3608                GuidList.pop(TokenSpace)
3609        CheckList = (GuidList, self.PpiList, self.ProtocolList, PcdCheckList)
3610        for Package in self.DerivedPackageList:
3611            if Package in Packages:
3612                continue
3613            BeChecked = (Package.Guids, Package.Ppis, Package.Protocols, Package.Pcds)
3614            Found = False
3615            for Index in range(len(BeChecked)):
3616                for Item in CheckList[Index]:
3617                    if Item in BeChecked[Index]:
3618                        Packages.append(Package)
3619                        Found = True
3620                        break
3621                if Found:
3622                    break
3623
3624        VfrPcds = self._GetPcdsMaybeUsedByVfr()
3625        for Pkg in self.PlatformInfo.PackageList:
3626            if Pkg in Packages:
3627                continue
3628            for VfrPcd in VfrPcds:
3629                if ((VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX) in Pkg.Pcds or
3630                    (VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC) in Pkg.Pcds):
3631                    Packages.append(Pkg)
3632                    break
3633
3634        ModuleType = SUP_MODULE_DXE_DRIVER if self.ModuleType == SUP_MODULE_UEFI_DRIVER and self.DepexGenerated else self.ModuleType
3635        DriverType = self.PcdIsDriver if self.PcdIsDriver else ''
3636        Guid = self.Guid
3637        MDefs = self.Module.Defines
3638
3639        AsBuiltInfDict = {
3640          'module_name'                       : self.Name,
3641          'module_guid'                       : Guid,
3642          'module_module_type'                : ModuleType,
3643          'module_version_string'             : [MDefs['VERSION_STRING']] if 'VERSION_STRING' in MDefs else [],
3644          'pcd_is_driver_string'              : [],
3645          'module_uefi_specification_version' : [],
3646          'module_pi_specification_version'   : [],
3647          'module_entry_point'                : self.Module.ModuleEntryPointList,
3648          'module_unload_image'               : self.Module.ModuleUnloadImageList,
3649          'module_constructor'                : self.Module.ConstructorList,
3650          'module_destructor'                 : self.Module.DestructorList,
3651          'module_shadow'                     : [MDefs['SHADOW']] if 'SHADOW' in MDefs else [],
3652          'module_pci_vendor_id'              : [MDefs['PCI_VENDOR_ID']] if 'PCI_VENDOR_ID' in MDefs else [],
3653          'module_pci_device_id'              : [MDefs['PCI_DEVICE_ID']] if 'PCI_DEVICE_ID' in MDefs else [],
3654          'module_pci_class_code'             : [MDefs['PCI_CLASS_CODE']] if 'PCI_CLASS_CODE' in MDefs else [],
3655          'module_pci_revision'               : [MDefs['PCI_REVISION']] if 'PCI_REVISION' in MDefs else [],
3656          'module_build_number'               : [MDefs['BUILD_NUMBER']] if 'BUILD_NUMBER' in MDefs else [],
3657          'module_spec'                       : [MDefs['SPEC']] if 'SPEC' in MDefs else [],
3658          'module_uefi_hii_resource_section'  : [MDefs['UEFI_HII_RESOURCE_SECTION']] if 'UEFI_HII_RESOURCE_SECTION' in MDefs else [],
3659          'module_uni_file'                   : [MDefs['MODULE_UNI_FILE']] if 'MODULE_UNI_FILE' in MDefs else [],
3660          'module_arch'                       : self.Arch,
3661          'package_item'                      : [Package.MetaFile.File.replace('\\', '/') for Package in Packages],
3662          'binary_item'                       : [],
3663          'patchablepcd_item'                 : [],
3664          'pcd_item'                          : [],
3665          'protocol_item'                     : [],
3666          'ppi_item'                          : [],
3667          'guid_item'                         : [],
3668          'flags_item'                        : [],
3669          'libraryclasses_item'               : []
3670        }
3671
3672        if 'MODULE_UNI_FILE' in MDefs:
3673            UNIFile = os.path.join(self.MetaFile.Dir, MDefs['MODULE_UNI_FILE'])
3674            if os.path.isfile(UNIFile):
3675                shutil.copy2(UNIFile, self.OutputDir)
3676
3677        if self.AutoGenVersion > int(gInfSpecVersion, 0):
3678            AsBuiltInfDict['module_inf_version'] = '0x%08x' % self.AutoGenVersion
3679        else:
3680            AsBuiltInfDict['module_inf_version'] = gInfSpecVersion
3681
3682        if DriverType:
3683            AsBuiltInfDict['pcd_is_driver_string'].append(DriverType)
3684
3685        if 'UEFI_SPECIFICATION_VERSION' in self.Specification:
3686            AsBuiltInfDict['module_uefi_specification_version'].append(self.Specification['UEFI_SPECIFICATION_VERSION'])
3687        if 'PI_SPECIFICATION_VERSION' in self.Specification:
3688            AsBuiltInfDict['module_pi_specification_version'].append(self.Specification['PI_SPECIFICATION_VERSION'])
3689
3690        OutputDir = self.OutputDir.replace('\\', '/').strip('/')
3691        DebugDir = self.DebugDir.replace('\\', '/').strip('/')
3692        for Item in self.CodaTargetList:
3693            File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')
3694            self.OutputFile.add(File)
3695            if os.path.isabs(File):
3696                File = File.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/')
3697            if Item.Target.Ext.lower() == '.aml':
3698                AsBuiltInfDict['binary_item'].append('ASL|' + File)
3699            elif Item.Target.Ext.lower() == '.acpi':
3700                AsBuiltInfDict['binary_item'].append('ACPI|' + File)
3701            elif Item.Target.Ext.lower() == '.efi':
3702                AsBuiltInfDict['binary_item'].append('PE32|' + self.Name + '.efi')
3703            else:
3704                AsBuiltInfDict['binary_item'].append('BIN|' + File)
3705        if not self.DepexGenerated:
3706            DepexFile = os.path.join(self.OutputDir, self.Name + '.depex')
3707            if os.path.exists(DepexFile):
3708                self.DepexGenerated = True
3709        if self.DepexGenerated:
3710            self.OutputFile.add(self.Name + '.depex')
3711            if self.ModuleType in [SUP_MODULE_PEIM]:
3712                AsBuiltInfDict['binary_item'].append('PEI_DEPEX|' + self.Name + '.depex')
3713            elif self.ModuleType in [SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_UEFI_DRIVER]:
3714                AsBuiltInfDict['binary_item'].append('DXE_DEPEX|' + self.Name + '.depex')
3715            elif self.ModuleType in [SUP_MODULE_DXE_SMM_DRIVER]:
3716                AsBuiltInfDict['binary_item'].append('SMM_DEPEX|' + self.Name + '.depex')
3717
3718        Bin = self._GenOffsetBin()
3719        if Bin:
3720            AsBuiltInfDict['binary_item'].append('BIN|%s' % Bin)
3721            self.OutputFile.add(Bin)
3722
3723        for Root, Dirs, Files in os.walk(OutputDir):
3724            for File in Files:
3725                if File.lower().endswith('.pdb'):
3726                    AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File)
3727                    self.OutputFile.add(File)
3728        HeaderComments = self.Module.HeaderComments
3729        StartPos = 0
3730        for Index in range(len(HeaderComments)):
3731            if HeaderComments[Index].find('@BinaryHeader') != -1:
3732                HeaderComments[Index] = HeaderComments[Index].replace('@BinaryHeader', '@file')
3733                StartPos = Index
3734                break
3735        AsBuiltInfDict['header_comments'] = '\n'.join(HeaderComments[StartPos:]).replace(':#', '://')
3736        AsBuiltInfDict['tail_comments'] = '\n'.join(self.Module.TailComments)
3737
3738        GenList = [
3739            (self.ProtocolList, self._ProtocolComments, 'protocol_item'),
3740            (self.PpiList, self._PpiComments, 'ppi_item'),
3741            (GuidList, self._GuidComments, 'guid_item')
3742        ]
3743        for Item in GenList:
3744            for CName in Item[0]:
3745                Comments = '\n  '.join(Item[1][CName]) if CName in Item[1] else ''
3746                Entry = Comments + '\n  ' + CName if Comments else CName
3747                AsBuiltInfDict[Item[2]].append(Entry)
3748        PatchList = parsePcdInfoFromMapFile(
3749                            os.path.join(self.OutputDir, self.Name + '.map'),
3750                            os.path.join(self.OutputDir, self.Name + '.efi')
3751                        )
3752        if PatchList:
3753            for Pcd in PatchablePcds:
3754                TokenCName = Pcd.TokenCName
3755                for PcdItem in GlobalData.MixedPcd:
3756                    if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3757                        TokenCName = PcdItem[0]
3758                        break
3759                for PatchPcd in PatchList:
3760                    if TokenCName == PatchPcd[0]:
3761                        break
3762                else:
3763                    continue
3764                PcdValue = ''
3765                if Pcd.DatumType == 'BOOLEAN':
3766                    BoolValue = Pcd.DefaultValue.upper()
3767                    if BoolValue == 'TRUE':
3768                        Pcd.DefaultValue = '1'
3769                    elif BoolValue == 'FALSE':
3770                        Pcd.DefaultValue = '0'
3771
3772                if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
3773                    HexFormat = '0x%02x'
3774                    if Pcd.DatumType == TAB_UINT16:
3775                        HexFormat = '0x%04x'
3776                    elif Pcd.DatumType == TAB_UINT32:
3777                        HexFormat = '0x%08x'
3778                    elif Pcd.DatumType == TAB_UINT64:
3779                        HexFormat = '0x%016x'
3780                    PcdValue = HexFormat % int(Pcd.DefaultValue, 0)
3781                else:
3782                    if Pcd.MaxDatumSize is None or Pcd.MaxDatumSize == '':
3783                        EdkLogger.error("build", AUTOGEN_ERROR,
3784                                        "Unknown [MaxDatumSize] of PCD [%s.%s]" % (Pcd.TokenSpaceGuidCName, TokenCName)
3785                                        )
3786                    ArraySize = int(Pcd.MaxDatumSize, 0)
3787                    PcdValue = Pcd.DefaultValue
3788                    if PcdValue[0] != '{':
3789                        Unicode = False
3790                        if PcdValue[0] == 'L':
3791                            Unicode = True
3792                        PcdValue = PcdValue.lstrip('L')
3793                        PcdValue = eval(PcdValue)
3794                        NewValue = '{'
3795                        for Index in range(0, len(PcdValue)):
3796                            if Unicode:
3797                                CharVal = ord(PcdValue[Index])
3798                                NewValue = NewValue + '0x%02x' % (CharVal & 0x00FF) + ', ' \
3799                                        + '0x%02x' % (CharVal >> 8) + ', '
3800                            else:
3801                                NewValue = NewValue + '0x%02x' % (ord(PcdValue[Index]) % 0x100) + ', '
3802                        Padding = '0x00, '
3803                        if Unicode:
3804                            Padding = Padding * 2
3805                            ArraySize = ArraySize // 2
3806                        if ArraySize < (len(PcdValue) + 1):
3807                            if Pcd.MaxSizeUserSet:
3808                                EdkLogger.error("build", AUTOGEN_ERROR,
3809                                            "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3810                                            )
3811                            else:
3812                                ArraySize = len(PcdValue) + 1
3813                        if ArraySize > len(PcdValue) + 1:
3814                            NewValue = NewValue + Padding * (ArraySize - len(PcdValue) - 1)
3815                        PcdValue = NewValue + Padding.strip().rstrip(',') + '}'
3816                    elif len(PcdValue.split(',')) <= ArraySize:
3817                        PcdValue = PcdValue.rstrip('}') + ', 0x00' * (ArraySize - len(PcdValue.split(',')))
3818                        PcdValue += '}'
3819                    else:
3820                        if Pcd.MaxSizeUserSet:
3821                            EdkLogger.error("build", AUTOGEN_ERROR,
3822                                        "The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
3823                                        )
3824                        else:
3825                            ArraySize = len(PcdValue) + 1
3826                PcdItem = '%s.%s|%s|0x%X' % \
3827                    (Pcd.TokenSpaceGuidCName, TokenCName, PcdValue, PatchPcd[1])
3828                PcdComments = ''
3829                if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3830                    PcdComments = '\n  '.join(self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName])
3831                if PcdComments:
3832                    PcdItem = PcdComments + '\n  ' + PcdItem
3833                AsBuiltInfDict['patchablepcd_item'].append(PcdItem)
3834
3835        for Pcd in Pcds + VfrPcds:
3836            PcdCommentList = []
3837            HiiInfo = ''
3838            TokenCName = Pcd.TokenCName
3839            for PcdItem in GlobalData.MixedPcd:
3840                if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
3841                    TokenCName = PcdItem[0]
3842                    break
3843            if Pcd.Type == TAB_PCDS_DYNAMIC_EX_HII:
3844                for SkuName in Pcd.SkuInfoList:
3845                    SkuInfo = Pcd.SkuInfoList[SkuName]
3846                    HiiInfo = '## %s|%s|%s' % (SkuInfo.VariableName, SkuInfo.VariableGuid, SkuInfo.VariableOffset)
3847                    break
3848            if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
3849                PcdCommentList = self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName][:]
3850            if HiiInfo:
3851                UsageIndex = -1
3852                UsageStr = ''
3853                for Index, Comment in enumerate(PcdCommentList):
3854                    for Usage in UsageList:
3855                        if Comment.find(Usage) != -1:
3856                            UsageStr = Usage
3857                            UsageIndex = Index
3858                            break
3859                if UsageIndex != -1:
3860                    PcdCommentList[UsageIndex] = '## %s %s %s' % (UsageStr, HiiInfo, PcdCommentList[UsageIndex].replace(UsageStr, ''))
3861                else:
3862                    PcdCommentList.append('## UNDEFINED ' + HiiInfo)
3863            PcdComments = '\n  '.join(PcdCommentList)
3864            PcdEntry = Pcd.TokenSpaceGuidCName + '.' + TokenCName
3865            if PcdComments:
3866                PcdEntry = PcdComments + '\n  ' + PcdEntry
3867            AsBuiltInfDict['pcd_item'].append(PcdEntry)
3868        for Item in self.BuildOption:
3869            if 'FLAGS' in self.BuildOption[Item]:
3870                AsBuiltInfDict['flags_item'].append('%s:%s_%s_%s_%s_FLAGS = %s' % (self.ToolChainFamily, self.BuildTarget, self.ToolChain, self.Arch, Item, self.BuildOption[Item]['FLAGS'].strip()))
3871
3872        # Generated LibraryClasses section in comments.
3873        for Library in self.LibraryAutoGenList:
3874            AsBuiltInfDict['libraryclasses_item'].append(Library.MetaFile.File.replace('\\', '/'))
3875
3876        # Generated UserExtensions TianoCore section.
3877        # All tianocore user extensions are copied.
3878        UserExtStr = ''
3879        for TianoCore in self._GetTianoCoreUserExtensionList():
3880            UserExtStr += '\n'.join(TianoCore)
3881            ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])
3882            if os.path.isfile(ExtensionFile):
3883                shutil.copy2(ExtensionFile, self.OutputDir)
3884        AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr
3885
3886        # Generated depex expression section in comments.
3887        DepexExpression = self._GetDepexExpresionString()
3888        AsBuiltInfDict['depexsection_item'] = DepexExpression if DepexExpression else ''
3889
3890        AsBuiltInf = TemplateString()
3891        AsBuiltInf.Append(gAsBuiltInfHeaderString.Replace(AsBuiltInfDict))
3892
3893        SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)
3894
3895        self.IsAsBuiltInfCreated = True
3896        if GlobalData.gBinCacheDest:
3897            self.CopyModuleToCache()
3898
3899    def CopyModuleToCache(self):
3900        FileDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3901        CreateDirectory (FileDir)
3902        HashFile = path.join(self.BuildDir, self.Name + '.hash')
3903        if os.path.exists(HashFile):
3904            shutil.copy2(HashFile, FileDir)
3905        if not self.IsLibrary:
3906            ModuleFile = path.join(self.OutputDir, self.Name + '.inf')
3907            if os.path.exists(ModuleFile):
3908                shutil.copy2(ModuleFile, FileDir)
3909        else:
3910            OutputDir = self.OutputDir.replace('\\', '/').strip('/')
3911            DebugDir = self.DebugDir.replace('\\', '/').strip('/')
3912            for Item in self.CodaTargetList:
3913                File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')
3914                self.OutputFile.add(File)
3915        if not self.OutputFile:
3916            Ma = self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
3917            self.OutputFile = Ma.Binaries
3918        if self.OutputFile:
3919            for File in self.OutputFile:
3920                File = str(File)
3921                if not os.path.isabs(File):
3922                    File = os.path.join(self.OutputDir, File)
3923                if os.path.exists(File):
3924                    sub_dir = os.path.relpath(File, self.OutputDir)
3925                    destination_file = os.path.join(FileDir, sub_dir)
3926                    destination_dir = os.path.dirname(destination_file)
3927                    CreateDirectory(destination_dir)
3928                    shutil.copy2(File, destination_dir)
3929
3930    def AttemptModuleCacheCopy(self):
3931        # If library or Module is binary do not skip by hash
3932        if self.IsBinaryModule:
3933            return False
3934        # .inc is contains binary information so do not skip by hash as well
3935        for f_ext in self.SourceFileList:
3936            if '.inc' in str(f_ext):
3937                return False
3938        FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)
3939        HashFile = path.join(FileDir, self.Name + '.hash')
3940        if os.path.exists(HashFile):
3941            f = open(HashFile, 'r')
3942            CacheHash = f.read()
3943            f.close()
3944            self.GenModuleHash()
3945            if GlobalData.gModuleHash[self.Arch][self.Name]:
3946                if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:
3947                    for root, dir, files in os.walk(FileDir):
3948                        for f in files:
3949                            if self.Name + '.hash' in f:
3950                                shutil.copy(HashFile, self.BuildDir)
3951                            else:
3952                                File = path.join(root, f)
3953                                sub_dir = os.path.relpath(File, FileDir)
3954                                destination_file = os.path.join(self.OutputDir, sub_dir)
3955                                destination_dir = os.path.dirname(destination_file)
3956                                CreateDirectory(destination_dir)
3957                                shutil.copy(File, destination_dir)
3958                    if self.Name == "PcdPeim" or self.Name == "PcdDxe":
3959                        CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
3960                    return True
3961        return False
3962
3963    ## Create makefile for the module and its dependent libraries
3964    #
3965    #   @param      CreateLibraryMakeFile   Flag indicating if or not the makefiles of
3966    #                                       dependent libraries will be created
3967    #
3968    @cached_class_function
3969    def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []):
3970        # nest this function inside it's only caller.
3971        def CreateTimeStamp():
3972            FileSet = {self.MetaFile.Path}
3973
3974            for SourceFile in self.Module.Sources:
3975                FileSet.add (SourceFile.Path)
3976
3977            for Lib in self.DependentLibraryList:
3978                FileSet.add (Lib.MetaFile.Path)
3979
3980            for f in self.AutoGenDepSet:
3981                FileSet.add (f.Path)
3982
3983            if os.path.exists (self.TimeStampPath):
3984                os.remove (self.TimeStampPath)
3985            with open(self.TimeStampPath, 'w+') as file:
3986                for f in FileSet:
3987                    print(f, file=file)
3988
3989        # Ignore generating makefile when it is a binary module
3990        if self.IsBinaryModule:
3991            return
3992
3993        self.GenFfsList = GenFfsList
3994        if not self.IsLibrary and CreateLibraryMakeFile:
3995            for LibraryAutoGen in self.LibraryAutoGenList:
3996                LibraryAutoGen.CreateMakeFile()
3997
3998        if self.CanSkip():
3999            return
4000
4001        if len(self.CustomMakefile) == 0:
4002            Makefile = GenMake.ModuleMakefile(self)
4003        else:
4004            Makefile = GenMake.CustomMakefile(self)
4005        if Makefile.Generate():
4006            EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" %
4007                            (self.Name, self.Arch))
4008        else:
4009            EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %
4010                            (self.Name, self.Arch))
4011
4012        CreateTimeStamp()
4013
4014    def CopyBinaryFiles(self):
4015        for File in self.Module.Binaries:
4016            SrcPath = File.Path
4017            DstPath = os.path.join(self.OutputDir, os.path.basename(SrcPath))
4018            CopyLongFilePath(SrcPath, DstPath)
4019    ## Create autogen code for the module and its dependent libraries
4020    #
4021    #   @param      CreateLibraryCodeFile   Flag indicating if or not the code of
4022    #                                       dependent libraries will be created
4023    #
4024    def CreateCodeFile(self, CreateLibraryCodeFile=True):
4025        if self.IsCodeFileCreated:
4026            return
4027
4028        # Need to generate PcdDatabase even PcdDriver is binarymodule
4029        if self.IsBinaryModule and self.PcdIsDriver != '':
4030            CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
4031            return
4032        if self.IsBinaryModule:
4033            if self.IsLibrary:
4034                self.CopyBinaryFiles()
4035            return
4036
4037        if not self.IsLibrary and CreateLibraryCodeFile:
4038            for LibraryAutoGen in self.LibraryAutoGenList:
4039                LibraryAutoGen.CreateCodeFile()
4040
4041        if self.CanSkip():
4042            return
4043
4044        AutoGenList = []
4045        IgoredAutoGenList = []
4046
4047        for File in self.AutoGenFileList:
4048            if GenC.Generate(File.Path, self.AutoGenFileList[File], File.IsBinary):
4049                AutoGenList.append(str(File))
4050            else:
4051                IgoredAutoGenList.append(str(File))
4052
4053
4054        for ModuleType in self.DepexList:
4055            # Ignore empty [depex] section or [depex] section for SUP_MODULE_USER_DEFINED module
4056            if len(self.DepexList[ModuleType]) == 0 or ModuleType == SUP_MODULE_USER_DEFINED:
4057                continue
4058
4059            Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True)
4060            DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name}
4061
4062            if len(Dpx.PostfixNotation) != 0:
4063                self.DepexGenerated = True
4064
4065            if Dpx.Generate(path.join(self.OutputDir, DpxFile)):
4066                AutoGenList.append(str(DpxFile))
4067            else:
4068                IgoredAutoGenList.append(str(DpxFile))
4069
4070        if IgoredAutoGenList == []:
4071            EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" %
4072                            (" ".join(AutoGenList), self.Name, self.Arch))
4073        elif AutoGenList == []:
4074            EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" %
4075                            (" ".join(IgoredAutoGenList), self.Name, self.Arch))
4076        else:
4077            EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" %
4078                            (" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch))
4079
4080        self.IsCodeFileCreated = True
4081        return AutoGenList
4082
4083    ## Summarize the ModuleAutoGen objects of all libraries used by this module
4084    @cached_property
4085    def LibraryAutoGenList(self):
4086        RetVal = []
4087        for Library in self.DependentLibraryList:
4088            La = ModuleAutoGen(
4089                        self.Workspace,
4090                        Library.MetaFile,
4091                        self.BuildTarget,
4092                        self.ToolChain,
4093                        self.Arch,
4094                        self.PlatformInfo.MetaFile
4095                        )
4096            if La not in RetVal:
4097                RetVal.append(La)
4098                for Lib in La.CodaTargetList:
4099                    self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)
4100        return RetVal
4101
4102    def GenModuleHash(self):
4103        # Initialize a dictionary for each arch type
4104        if self.Arch not in GlobalData.gModuleHash:
4105            GlobalData.gModuleHash[self.Arch] = {}
4106
4107        # Early exit if module or library has been hashed and is in memory
4108        if self.Name in GlobalData.gModuleHash[self.Arch]:
4109            return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8')
4110
4111        # Initialze hash object
4112        m = hashlib.md5()
4113
4114        # Add Platform level hash
4115        m.update(GlobalData.gPlatformHash.encode('utf-8'))
4116
4117        # Add Package level hash
4118        if self.DependentPackageList:
4119            for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
4120                if Pkg.PackageName in GlobalData.gPackageHash:
4121                    m.update(GlobalData.gPackageHash[Pkg.PackageName].encode('utf-8'))
4122
4123        # Add Library hash
4124        if self.LibraryAutoGenList:
4125            for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
4126                if Lib.Name not in GlobalData.gModuleHash[self.Arch]:
4127                    Lib.GenModuleHash()
4128                m.update(GlobalData.gModuleHash[self.Arch][Lib.Name].encode('utf-8'))
4129
4130        # Add Module self
4131        f = open(str(self.MetaFile), 'rb')
4132        Content = f.read()
4133        f.close()
4134        m.update(Content)
4135
4136        # Add Module's source files
4137        if self.SourceFileList:
4138            for File in sorted(self.SourceFileList, key=lambda x: str(x)):
4139                f = open(str(File), 'rb')
4140                Content = f.read()
4141                f.close()
4142                m.update(Content)
4143
4144        GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
4145
4146        return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8')
4147
4148    ## Decide whether we can skip the ModuleAutoGen process
4149    def CanSkipbyHash(self):
4150        # Hashing feature is off
4151        if not GlobalData.gUseHashCache:
4152            return False
4153
4154        # Initialize a dictionary for each arch type
4155        if self.Arch not in GlobalData.gBuildHashSkipTracking:
4156            GlobalData.gBuildHashSkipTracking[self.Arch] = dict()
4157
4158        # If library or Module is binary do not skip by hash
4159        if self.IsBinaryModule:
4160            return False
4161
4162        # .inc is contains binary information so do not skip by hash as well
4163        for f_ext in self.SourceFileList:
4164            if '.inc' in str(f_ext):
4165                return False
4166
4167        # Use Cache, if exists and if Module has a copy in cache
4168        if GlobalData.gBinCacheSource and self.AttemptModuleCacheCopy():
4169            return True
4170
4171        # Early exit for libraries that haven't yet finished building
4172        HashFile = path.join(self.BuildDir, self.Name + ".hash")
4173        if self.IsLibrary and not os.path.exists(HashFile):
4174            return False
4175
4176        # Return a Boolean based on if can skip by hash, either from memory or from IO.
4177        if self.Name not in GlobalData.gBuildHashSkipTracking[self.Arch]:
4178            # If hashes are the same, SaveFileOnChange() will return False.
4179            GlobalData.gBuildHashSkipTracking[self.Arch][self.Name] = not SaveFileOnChange(HashFile, self.GenModuleHash(), True)
4180            return GlobalData.gBuildHashSkipTracking[self.Arch][self.Name]
4181        else:
4182            return GlobalData.gBuildHashSkipTracking[self.Arch][self.Name]
4183
4184    ## Decide whether we can skip the ModuleAutoGen process
4185    #  If any source file is newer than the module than we cannot skip
4186    #
4187    def CanSkip(self):
4188        if self.MakeFileDir in GlobalData.gSikpAutoGenCache:
4189            return True
4190        if not os.path.exists(self.TimeStampPath):
4191            return False
4192        #last creation time of the module
4193        DstTimeStamp = os.stat(self.TimeStampPath)[8]
4194
4195        SrcTimeStamp = self.Workspace._SrcTimeStamp
4196        if SrcTimeStamp > DstTimeStamp:
4197            return False
4198
4199        with open(self.TimeStampPath,'r') as f:
4200            for source in f:
4201                source = source.rstrip('\n')
4202                if not os.path.exists(source):
4203                    return False
4204                if source not in ModuleAutoGen.TimeDict :
4205                    ModuleAutoGen.TimeDict[source] = os.stat(source)[8]
4206                if ModuleAutoGen.TimeDict[source] > DstTimeStamp:
4207                    return False
4208        GlobalData.gSikpAutoGenCache.add(self.MakeFileDir)
4209        return True
4210
4211    @cached_property
4212    def TimeStampPath(self):
4213        return os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')
4214