mirror of
https://github.com/acidanthera/audk.git
synced 2025-04-08 17:05:09 +02:00
Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2216 This patch is going to fix the lib order in static_library_files.lst. This issue is introduced by commit 673d09a2dd. Before 673d09a2dd, build tool apply build rule for the module's library firstly and then apply build rule for module itself. Now, build tool apply build rule for module self and then for its library. That behavior impact the lib order in static_library_files.lst. This patch is to call module's LibraryAutoGenList function explicitly, where the applying build rule action for library is triggered. Cc: Liming Gao <liming.gao@intel.com> Cc: dann frazier <dann.frazier@canonical.com> Signed-off-by: Bob Feng <bob.c.feng@intel.com> Tested-by: dann frazier <dann.frazier@canonical.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
2566 lines
111 KiB
Python
Executable File
2566 lines
111 KiB
Python
Executable File
## @file
|
|
# Create makefile for MS nmake and GNU make
|
|
#
|
|
# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
#
|
|
from __future__ import absolute_import
|
|
from AutoGen.AutoGen import AutoGen
|
|
from Common.LongFilePathSupport import CopyLongFilePath
|
|
from Common.BuildToolError import *
|
|
from Common.DataType import *
|
|
from Common.Misc import *
|
|
from Common.StringUtils import NormPath,GetSplitList
|
|
from collections import defaultdict
|
|
from Workspace.WorkspaceCommon import OrderedListDict
|
|
import os.path as path
|
|
import copy
|
|
import hashlib
|
|
from . import InfSectionParser
|
|
from . import GenC
|
|
from . import GenMake
|
|
from . import GenDepex
|
|
from io import BytesIO
|
|
from GenPatchPcdTable.GenPatchPcdTable import parsePcdInfoFromMapFile
|
|
from Workspace.MetaFileCommentParser import UsageList
|
|
from .GenPcdDb import CreatePcdDatabaseCode
|
|
from Common.caching import cached_class_function
|
|
from AutoGen.ModuleAutoGenHelper import PlatformInfo,WorkSpaceInfo
|
|
from AutoGen.CacheIR import ModuleBuildCacheIR
|
|
import json
|
|
import tempfile
|
|
|
|
## Mapping Makefile type
|
|
gMakeTypeMap = {TAB_COMPILER_MSFT:"nmake", "GCC":"gmake"}
|
|
#
|
|
# Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
|
|
# is the former use /I , the Latter used -I to specify include directories
|
|
#
|
|
gBuildOptIncludePatternMsft = re.compile(r"(?:.*?)/I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)
|
|
gBuildOptIncludePatternOther = re.compile(r"(?:.*?)-I[ \t]*([^ ]*)", re.MULTILINE | re.DOTALL)
|
|
|
|
## default file name for AutoGen
|
|
gAutoGenCodeFileName = "AutoGen.c"
|
|
gAutoGenHeaderFileName = "AutoGen.h"
|
|
gAutoGenStringFileName = "%(module_name)sStrDefs.h"
|
|
gAutoGenStringFormFileName = "%(module_name)sStrDefs.hpk"
|
|
gAutoGenDepexFileName = "%(module_name)s.depex"
|
|
gAutoGenImageDefFileName = "%(module_name)sImgDefs.h"
|
|
gAutoGenIdfFileName = "%(module_name)sIdf.hpk"
|
|
gInfSpecVersion = "0x00010017"
|
|
|
|
#
|
|
# Match name = variable
|
|
#
|
|
gEfiVarStoreNamePattern = re.compile("\s*name\s*=\s*(\w+)")
|
|
#
|
|
# The format of guid in efivarstore statement likes following and must be correct:
|
|
# guid = {0xA04A27f4, 0xDF00, 0x4D42, {0xB5, 0x52, 0x39, 0x51, 0x13, 0x02, 0x11, 0x3D}}
|
|
#
|
|
gEfiVarStoreGuidPattern = re.compile("\s*guid\s*=\s*({.*?{.*?}\s*})")
|
|
|
|
#
|
|
# Template string to generic AsBuilt INF
|
|
#
|
|
gAsBuiltInfHeaderString = TemplateString("""${header_comments}
|
|
|
|
# DO NOT EDIT
|
|
# FILE auto-generated
|
|
|
|
[Defines]
|
|
INF_VERSION = ${module_inf_version}
|
|
BASE_NAME = ${module_name}
|
|
FILE_GUID = ${module_guid}
|
|
MODULE_TYPE = ${module_module_type}${BEGIN}
|
|
VERSION_STRING = ${module_version_string}${END}${BEGIN}
|
|
PCD_IS_DRIVER = ${pcd_is_driver_string}${END}${BEGIN}
|
|
UEFI_SPECIFICATION_VERSION = ${module_uefi_specification_version}${END}${BEGIN}
|
|
PI_SPECIFICATION_VERSION = ${module_pi_specification_version}${END}${BEGIN}
|
|
ENTRY_POINT = ${module_entry_point}${END}${BEGIN}
|
|
UNLOAD_IMAGE = ${module_unload_image}${END}${BEGIN}
|
|
CONSTRUCTOR = ${module_constructor}${END}${BEGIN}
|
|
DESTRUCTOR = ${module_destructor}${END}${BEGIN}
|
|
SHADOW = ${module_shadow}${END}${BEGIN}
|
|
PCI_VENDOR_ID = ${module_pci_vendor_id}${END}${BEGIN}
|
|
PCI_DEVICE_ID = ${module_pci_device_id}${END}${BEGIN}
|
|
PCI_CLASS_CODE = ${module_pci_class_code}${END}${BEGIN}
|
|
PCI_REVISION = ${module_pci_revision}${END}${BEGIN}
|
|
BUILD_NUMBER = ${module_build_number}${END}${BEGIN}
|
|
SPEC = ${module_spec}${END}${BEGIN}
|
|
UEFI_HII_RESOURCE_SECTION = ${module_uefi_hii_resource_section}${END}${BEGIN}
|
|
MODULE_UNI_FILE = ${module_uni_file}${END}
|
|
|
|
[Packages.${module_arch}]${BEGIN}
|
|
${package_item}${END}
|
|
|
|
[Binaries.${module_arch}]${BEGIN}
|
|
${binary_item}${END}
|
|
|
|
[PatchPcd.${module_arch}]${BEGIN}
|
|
${patchablepcd_item}
|
|
${END}
|
|
|
|
[Protocols.${module_arch}]${BEGIN}
|
|
${protocol_item}
|
|
${END}
|
|
|
|
[Ppis.${module_arch}]${BEGIN}
|
|
${ppi_item}
|
|
${END}
|
|
|
|
[Guids.${module_arch}]${BEGIN}
|
|
${guid_item}
|
|
${END}
|
|
|
|
[PcdEx.${module_arch}]${BEGIN}
|
|
${pcd_item}
|
|
${END}
|
|
|
|
[LibraryClasses.${module_arch}]
|
|
## @LIB_INSTANCES${BEGIN}
|
|
# ${libraryclasses_item}${END}
|
|
|
|
${depexsection_item}
|
|
|
|
${userextension_tianocore_item}
|
|
|
|
${tail_comments}
|
|
|
|
[BuildOptions.${module_arch}]
|
|
## @AsBuilt${BEGIN}
|
|
## ${flags_item}${END}
|
|
""")
|
|
#
|
|
# extend lists contained in a dictionary with lists stored in another dictionary
|
|
# if CopyToDict is not derived from DefaultDict(list) then this may raise exception
|
|
#
|
|
def ExtendCopyDictionaryLists(CopyToDict, CopyFromDict):
|
|
for Key in CopyFromDict:
|
|
CopyToDict[Key].extend(CopyFromDict[Key])
|
|
|
|
# Create a directory specified by a set of path elements and return the full path
|
|
def _MakeDir(PathList):
|
|
RetVal = path.join(*PathList)
|
|
CreateDirectory(RetVal)
|
|
return RetVal
|
|
|
|
#
|
|
# Convert string to C format array
|
|
#
|
|
def _ConvertStringToByteArray(Value):
|
|
Value = Value.strip()
|
|
if not Value:
|
|
return None
|
|
if Value[0] == '{':
|
|
if not Value.endswith('}'):
|
|
return None
|
|
Value = Value.replace(' ', '').replace('{', '').replace('}', '')
|
|
ValFields = Value.split(',')
|
|
try:
|
|
for Index in range(len(ValFields)):
|
|
ValFields[Index] = str(int(ValFields[Index], 0))
|
|
except ValueError:
|
|
return None
|
|
Value = '{' + ','.join(ValFields) + '}'
|
|
return Value
|
|
|
|
Unicode = False
|
|
if Value.startswith('L"'):
|
|
if not Value.endswith('"'):
|
|
return None
|
|
Value = Value[1:]
|
|
Unicode = True
|
|
elif not Value.startswith('"') or not Value.endswith('"'):
|
|
return None
|
|
|
|
Value = eval(Value) # translate escape character
|
|
NewValue = '{'
|
|
for Index in range(0, len(Value)):
|
|
if Unicode:
|
|
NewValue = NewValue + str(ord(Value[Index]) % 0x10000) + ','
|
|
else:
|
|
NewValue = NewValue + str(ord(Value[Index]) % 0x100) + ','
|
|
Value = NewValue + '0}'
|
|
return Value
|
|
|
|
## ModuleAutoGen class
|
|
#
|
|
# This class encapsules the AutoGen behaviors for the build tools. In addition to
|
|
# the generation of AutoGen.h and AutoGen.c, it will generate *.depex file according
|
|
# to the [depex] section in module's inf file.
|
|
#
|
|
class ModuleAutoGen(AutoGen):
|
|
# call super().__init__ then call the worker function with different parameter count
|
|
def __init__(self, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
|
|
if not hasattr(self, "_Init"):
|
|
self._InitWorker(Workspace, MetaFile, Target, Toolchain, Arch, *args)
|
|
self._Init = True
|
|
|
|
## Cache the timestamps of metafiles of every module in a class attribute
|
|
#
|
|
TimeDict = {}
|
|
|
|
def __new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs):
|
|
# check if this module is employed by active platform
|
|
if not PlatformInfo(Workspace, args[0], Target, Toolchain, Arch,args[-1]).ValidModule(MetaFile):
|
|
EdkLogger.verbose("Module [%s] for [%s] is not employed by active platform\n" \
|
|
% (MetaFile, Arch))
|
|
return None
|
|
return super(ModuleAutoGen, cls).__new__(cls, Workspace, MetaFile, Target, Toolchain, Arch, *args, **kwargs)
|
|
|
|
## Initialize ModuleAutoGen
|
|
#
|
|
# @param Workspace EdkIIWorkspaceBuild object
|
|
# @param ModuleFile The path of module file
|
|
# @param Target Build target (DEBUG, RELEASE)
|
|
# @param Toolchain Name of tool chain
|
|
# @param Arch The arch the module supports
|
|
# @param PlatformFile Platform meta-file
|
|
#
|
|
def _InitWorker(self, Workspace, ModuleFile, Target, Toolchain, Arch, PlatformFile,DataPipe):
|
|
EdkLogger.debug(EdkLogger.DEBUG_9, "AutoGen module [%s] [%s]" % (ModuleFile, Arch))
|
|
GlobalData.gProcessingFile = "%s [%s, %s, %s]" % (ModuleFile, Arch, Toolchain, Target)
|
|
|
|
self.Workspace = Workspace
|
|
self.WorkspaceDir = ""
|
|
self.PlatformInfo = None
|
|
self.DataPipe = DataPipe
|
|
self.__init_platform_info__()
|
|
self.MetaFile = ModuleFile
|
|
self.SourceDir = self.MetaFile.SubDir
|
|
self.SourceDir = mws.relpath(self.SourceDir, self.WorkspaceDir)
|
|
|
|
self.ToolChain = Toolchain
|
|
self.BuildTarget = Target
|
|
self.Arch = Arch
|
|
self.ToolChainFamily = self.PlatformInfo.ToolChainFamily
|
|
self.BuildRuleFamily = self.PlatformInfo.BuildRuleFamily
|
|
|
|
self.IsCodeFileCreated = False
|
|
self.IsAsBuiltInfCreated = False
|
|
self.DepexGenerated = False
|
|
|
|
self.BuildDatabase = self.Workspace.BuildDatabase
|
|
self.BuildRuleOrder = None
|
|
self.BuildTime = 0
|
|
|
|
self._GuidComments = OrderedListDict()
|
|
self._ProtocolComments = OrderedListDict()
|
|
self._PpiComments = OrderedListDict()
|
|
self._BuildTargets = None
|
|
self._IntroBuildTargetList = None
|
|
self._FinalBuildTargetList = None
|
|
self._FileTypes = None
|
|
|
|
self.AutoGenDepSet = set()
|
|
self.ReferenceModules = []
|
|
self.ConstPcd = {}
|
|
self.Makefile = None
|
|
self.FileDependCache = {}
|
|
|
|
def __init_platform_info__(self):
|
|
pinfo = self.DataPipe.Get("P_Info")
|
|
self.WorkspaceDir = pinfo.get("WorkspaceDir")
|
|
self.PlatformInfo = PlatformInfo(self.Workspace,pinfo.get("ActivePlatform"),pinfo.get("Target"),pinfo.get("ToolChain"),pinfo.get("Arch"),self.DataPipe)
|
|
## hash() operator of ModuleAutoGen
|
|
#
|
|
# The module file path and arch string will be used to represent
|
|
# hash value of this object
|
|
#
|
|
# @retval int Hash value of the module file path and arch
|
|
#
|
|
@cached_class_function
|
|
def __hash__(self):
|
|
return hash((self.MetaFile, self.Arch))
|
|
def __repr__(self):
|
|
return "%s [%s]" % (self.MetaFile, self.Arch)
|
|
|
|
# Get FixedAtBuild Pcds of this Module
|
|
@cached_property
|
|
def FixedAtBuildPcds(self):
|
|
RetVal = []
|
|
for Pcd in self.ModulePcdList:
|
|
if Pcd.Type != TAB_PCDS_FIXED_AT_BUILD:
|
|
continue
|
|
if Pcd not in RetVal:
|
|
RetVal.append(Pcd)
|
|
return RetVal
|
|
|
|
@cached_property
|
|
def FixedVoidTypePcds(self):
|
|
RetVal = {}
|
|
for Pcd in self.FixedAtBuildPcds:
|
|
if Pcd.DatumType == TAB_VOID:
|
|
if '.'.join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName)) not in RetVal:
|
|
RetVal['.'.join((Pcd.TokenSpaceGuidCName, Pcd.TokenCName))] = Pcd.DefaultValue
|
|
return RetVal
|
|
|
|
@property
|
|
def UniqueBaseName(self):
|
|
ModuleNames = self.DataPipe.Get("M_Name")
|
|
if not ModuleNames:
|
|
return self.Name
|
|
return ModuleNames.get((self.Name,self.MetaFile),self.Name)
|
|
|
|
# Macros could be used in build_rule.txt (also Makefile)
|
|
@cached_property
|
|
def Macros(self):
|
|
return OrderedDict((
|
|
("WORKSPACE" ,self.WorkspaceDir),
|
|
("MODULE_NAME" ,self.Name),
|
|
("MODULE_NAME_GUID" ,self.UniqueBaseName),
|
|
("MODULE_GUID" ,self.Guid),
|
|
("MODULE_VERSION" ,self.Version),
|
|
("MODULE_TYPE" ,self.ModuleType),
|
|
("MODULE_FILE" ,str(self.MetaFile)),
|
|
("MODULE_FILE_BASE_NAME" ,self.MetaFile.BaseName),
|
|
("MODULE_RELATIVE_DIR" ,self.SourceDir),
|
|
("MODULE_DIR" ,self.SourceDir),
|
|
("BASE_NAME" ,self.Name),
|
|
("ARCH" ,self.Arch),
|
|
("TOOLCHAIN" ,self.ToolChain),
|
|
("TOOLCHAIN_TAG" ,self.ToolChain),
|
|
("TOOL_CHAIN_TAG" ,self.ToolChain),
|
|
("TARGET" ,self.BuildTarget),
|
|
("BUILD_DIR" ,self.PlatformInfo.BuildDir),
|
|
("BIN_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
|
|
("LIB_DIR" ,os.path.join(self.PlatformInfo.BuildDir, self.Arch)),
|
|
("MODULE_BUILD_DIR" ,self.BuildDir),
|
|
("OUTPUT_DIR" ,self.OutputDir),
|
|
("DEBUG_DIR" ,self.DebugDir),
|
|
("DEST_DIR_OUTPUT" ,self.OutputDir),
|
|
("DEST_DIR_DEBUG" ,self.DebugDir),
|
|
("PLATFORM_NAME" ,self.PlatformInfo.Name),
|
|
("PLATFORM_GUID" ,self.PlatformInfo.Guid),
|
|
("PLATFORM_VERSION" ,self.PlatformInfo.Version),
|
|
("PLATFORM_RELATIVE_DIR" ,self.PlatformInfo.SourceDir),
|
|
("PLATFORM_DIR" ,mws.join(self.WorkspaceDir, self.PlatformInfo.SourceDir)),
|
|
("PLATFORM_OUTPUT_DIR" ,self.PlatformInfo.OutputDir),
|
|
("FFS_OUTPUT_DIR" ,self.FfsOutputDir)
|
|
))
|
|
|
|
## Return the module build data object
|
|
@cached_property
|
|
def Module(self):
|
|
return self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
|
|
|
|
## Return the module name
|
|
@cached_property
|
|
def Name(self):
|
|
return self.Module.BaseName
|
|
|
|
## Return the module DxsFile if exist
|
|
@cached_property
|
|
def DxsFile(self):
|
|
return self.Module.DxsFile
|
|
|
|
## Return the module meta-file GUID
|
|
@cached_property
|
|
def Guid(self):
|
|
#
|
|
# To build same module more than once, the module path with FILE_GUID overridden has
|
|
# the file name FILE_GUIDmodule.inf, but the relative path (self.MetaFile.File) is the real path
|
|
# in DSC. The overridden GUID can be retrieved from file name
|
|
#
|
|
if os.path.basename(self.MetaFile.File) != os.path.basename(self.MetaFile.Path):
|
|
#
|
|
# Length of GUID is 36
|
|
#
|
|
return os.path.basename(self.MetaFile.Path)[:36]
|
|
return self.Module.Guid
|
|
|
|
## Return the module version
|
|
@cached_property
|
|
def Version(self):
|
|
return self.Module.Version
|
|
|
|
## Return the module type
|
|
@cached_property
|
|
def ModuleType(self):
|
|
return self.Module.ModuleType
|
|
|
|
## Return the component type (for Edk.x style of module)
|
|
@cached_property
|
|
def ComponentType(self):
|
|
return self.Module.ComponentType
|
|
|
|
## Return the build type
|
|
@cached_property
|
|
def BuildType(self):
|
|
return self.Module.BuildType
|
|
|
|
## Return the PCD_IS_DRIVER setting
|
|
@cached_property
|
|
def PcdIsDriver(self):
|
|
return self.Module.PcdIsDriver
|
|
|
|
## Return the autogen version, i.e. module meta-file version
|
|
@cached_property
|
|
def AutoGenVersion(self):
|
|
return self.Module.AutoGenVersion
|
|
|
|
## Check if the module is library or not
|
|
@cached_property
|
|
def IsLibrary(self):
|
|
return bool(self.Module.LibraryClass)
|
|
|
|
## Check if the module is binary module or not
|
|
@cached_property
|
|
def IsBinaryModule(self):
|
|
return self.Module.IsBinaryModule
|
|
|
|
## Return the directory to store intermediate files of the module
|
|
@cached_property
|
|
def BuildDir(self):
|
|
return _MakeDir((
|
|
self.PlatformInfo.BuildDir,
|
|
self.Arch,
|
|
self.SourceDir,
|
|
self.MetaFile.BaseName
|
|
))
|
|
|
|
## Return the directory to store the intermediate object files of the module
|
|
@cached_property
|
|
def OutputDir(self):
|
|
return _MakeDir((self.BuildDir, "OUTPUT"))
|
|
|
|
## Return the directory path to store ffs file
|
|
@cached_property
|
|
def FfsOutputDir(self):
|
|
if GlobalData.gFdfParser:
|
|
return path.join(self.PlatformInfo.BuildDir, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name)
|
|
return ''
|
|
|
|
## Return the directory to store auto-gened source files of the module
|
|
@cached_property
|
|
def DebugDir(self):
|
|
return _MakeDir((self.BuildDir, "DEBUG"))
|
|
|
|
## Return the path of custom file
|
|
@cached_property
|
|
def CustomMakefile(self):
|
|
RetVal = {}
|
|
for Type in self.Module.CustomMakefile:
|
|
MakeType = gMakeTypeMap[Type] if Type in gMakeTypeMap else 'nmake'
|
|
File = os.path.join(self.SourceDir, self.Module.CustomMakefile[Type])
|
|
RetVal[MakeType] = File
|
|
return RetVal
|
|
|
|
## Return the directory of the makefile
|
|
#
|
|
# @retval string The directory string of module's makefile
|
|
#
|
|
@cached_property
|
|
def MakeFileDir(self):
|
|
return self.BuildDir
|
|
|
|
## Return build command string
|
|
#
|
|
# @retval string Build command string
|
|
#
|
|
@cached_property
|
|
def BuildCommand(self):
|
|
return self.PlatformInfo.BuildCommand
|
|
|
|
## Get object list of all packages the module and its dependent libraries belong to
|
|
#
|
|
# @retval list The list of package object
|
|
#
|
|
@cached_property
|
|
def DerivedPackageList(self):
|
|
PackageList = []
|
|
for M in [self.Module] + self.DependentLibraryList:
|
|
for Package in M.Packages:
|
|
if Package in PackageList:
|
|
continue
|
|
PackageList.append(Package)
|
|
return PackageList
|
|
|
|
## Get the depex string
|
|
#
|
|
# @return : a string contain all depex expression.
|
|
def _GetDepexExpresionString(self):
|
|
DepexStr = ''
|
|
DepexList = []
|
|
## DPX_SOURCE IN Define section.
|
|
if self.Module.DxsFile:
|
|
return DepexStr
|
|
for M in [self.Module] + self.DependentLibraryList:
|
|
Filename = M.MetaFile.Path
|
|
InfObj = InfSectionParser.InfSectionParser(Filename)
|
|
DepexExpressionList = InfObj.GetDepexExpresionList()
|
|
for DepexExpression in DepexExpressionList:
|
|
for key in DepexExpression:
|
|
Arch, ModuleType = key
|
|
DepexExpr = [x for x in DepexExpression[key] if not str(x).startswith('#')]
|
|
# the type of build module is USER_DEFINED.
|
|
# All different DEPEX section tags would be copied into the As Built INF file
|
|
# and there would be separate DEPEX section tags
|
|
if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED or self.ModuleType.upper() == SUP_MODULE_HOST_APPLICATION:
|
|
if (Arch.upper() == self.Arch.upper()) and (ModuleType.upper() != TAB_ARCH_COMMON):
|
|
DepexList.append({(Arch, ModuleType): DepexExpr})
|
|
else:
|
|
if Arch.upper() == TAB_ARCH_COMMON or \
|
|
(Arch.upper() == self.Arch.upper() and \
|
|
ModuleType.upper() in [TAB_ARCH_COMMON, self.ModuleType.upper()]):
|
|
DepexList.append({(Arch, ModuleType): DepexExpr})
|
|
|
|
#the type of build module is USER_DEFINED.
|
|
if self.ModuleType.upper() == SUP_MODULE_USER_DEFINED or self.ModuleType.upper() == SUP_MODULE_HOST_APPLICATION:
|
|
for Depex in DepexList:
|
|
for key in Depex:
|
|
DepexStr += '[Depex.%s.%s]\n' % key
|
|
DepexStr += '\n'.join('# '+ val for val in Depex[key])
|
|
DepexStr += '\n\n'
|
|
if not DepexStr:
|
|
return '[Depex.%s]\n' % self.Arch
|
|
return DepexStr
|
|
|
|
#the type of build module not is USER_DEFINED.
|
|
Count = 0
|
|
for Depex in DepexList:
|
|
Count += 1
|
|
if DepexStr != '':
|
|
DepexStr += ' AND '
|
|
DepexStr += '('
|
|
for D in Depex.values():
|
|
DepexStr += ' '.join(val for val in D)
|
|
Index = DepexStr.find('END')
|
|
if Index > -1 and Index == len(DepexStr) - 3:
|
|
DepexStr = DepexStr[:-3]
|
|
DepexStr = DepexStr.strip()
|
|
DepexStr += ')'
|
|
if Count == 1:
|
|
DepexStr = DepexStr.lstrip('(').rstrip(')').strip()
|
|
if not DepexStr:
|
|
return '[Depex.%s]\n' % self.Arch
|
|
return '[Depex.%s]\n# ' % self.Arch + DepexStr
|
|
|
|
## Merge dependency expression
|
|
#
|
|
# @retval list The token list of the dependency expression after parsed
|
|
#
|
|
@cached_property
|
|
def DepexList(self):
|
|
if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
|
|
return {}
|
|
|
|
DepexList = []
|
|
#
|
|
# Append depex from dependent libraries, if not "BEFORE", "AFTER" expression
|
|
#
|
|
FixedVoidTypePcds = {}
|
|
for M in [self] + self.LibraryAutoGenList:
|
|
FixedVoidTypePcds.update(M.FixedVoidTypePcds)
|
|
for M in [self] + self.LibraryAutoGenList:
|
|
Inherited = False
|
|
for D in M.Module.Depex[self.Arch, self.ModuleType]:
|
|
if DepexList != []:
|
|
DepexList.append('AND')
|
|
DepexList.append('(')
|
|
#replace D with value if D is FixedAtBuild PCD
|
|
NewList = []
|
|
for item in D:
|
|
if '.' not in item:
|
|
NewList.append(item)
|
|
else:
|
|
try:
|
|
Value = FixedVoidTypePcds[item]
|
|
if len(Value.split(',')) != 16:
|
|
EdkLogger.error("build", FORMAT_INVALID,
|
|
"{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type and 16 bytes in the module.".format(item))
|
|
NewList.append(Value)
|
|
except:
|
|
EdkLogger.error("build", FORMAT_INVALID, "{} used in [Depex] section should be used as FixedAtBuild type and VOID* datum type in the module.".format(item))
|
|
|
|
DepexList.extend(NewList)
|
|
if DepexList[-1] == 'END': # no need of a END at this time
|
|
DepexList.pop()
|
|
DepexList.append(')')
|
|
Inherited = True
|
|
if Inherited:
|
|
EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.Module.BaseName, DepexList))
|
|
if 'BEFORE' in DepexList or 'AFTER' in DepexList:
|
|
break
|
|
if len(DepexList) > 0:
|
|
EdkLogger.verbose('')
|
|
return {self.ModuleType:DepexList}
|
|
|
|
## Merge dependency expression
|
|
#
|
|
# @retval list The token list of the dependency expression after parsed
|
|
#
|
|
@cached_property
|
|
def DepexExpressionDict(self):
|
|
if self.DxsFile or self.IsLibrary or TAB_DEPENDENCY_EXPRESSION_FILE in self.FileTypes:
|
|
return {}
|
|
|
|
DepexExpressionString = ''
|
|
#
|
|
# Append depex from dependent libraries, if not "BEFORE", "AFTER" expresion
|
|
#
|
|
for M in [self.Module] + self.DependentLibraryList:
|
|
Inherited = False
|
|
for D in M.DepexExpression[self.Arch, self.ModuleType]:
|
|
if DepexExpressionString != '':
|
|
DepexExpressionString += ' AND '
|
|
DepexExpressionString += '('
|
|
DepexExpressionString += D
|
|
DepexExpressionString = DepexExpressionString.rstrip('END').strip()
|
|
DepexExpressionString += ')'
|
|
Inherited = True
|
|
if Inherited:
|
|
EdkLogger.verbose("DEPEX[%s] (+%s) = %s" % (self.Name, M.BaseName, DepexExpressionString))
|
|
if 'BEFORE' in DepexExpressionString or 'AFTER' in DepexExpressionString:
|
|
break
|
|
if len(DepexExpressionString) > 0:
|
|
EdkLogger.verbose('')
|
|
|
|
return {self.ModuleType:DepexExpressionString}
|
|
|
|
# Get the tiano core user extension, it is contain dependent library.
|
|
# @retval: a list contain tiano core userextension.
|
|
#
|
|
def _GetTianoCoreUserExtensionList(self):
|
|
TianoCoreUserExtentionList = []
|
|
for M in [self.Module] + self.DependentLibraryList:
|
|
Filename = M.MetaFile.Path
|
|
InfObj = InfSectionParser.InfSectionParser(Filename)
|
|
TianoCoreUserExtenList = InfObj.GetUserExtensionTianoCore()
|
|
for TianoCoreUserExtent in TianoCoreUserExtenList:
|
|
for Section in TianoCoreUserExtent:
|
|
ItemList = Section.split(TAB_SPLIT)
|
|
Arch = self.Arch
|
|
if len(ItemList) == 4:
|
|
Arch = ItemList[3]
|
|
if Arch.upper() == TAB_ARCH_COMMON or Arch.upper() == self.Arch.upper():
|
|
TianoCoreList = []
|
|
TianoCoreList.extend([TAB_SECTION_START + Section + TAB_SECTION_END])
|
|
TianoCoreList.extend(TianoCoreUserExtent[Section][:])
|
|
TianoCoreList.append('\n')
|
|
TianoCoreUserExtentionList.append(TianoCoreList)
|
|
|
|
return TianoCoreUserExtentionList
|
|
|
|
## Return the list of specification version required for the module
|
|
#
|
|
# @retval list The list of specification defined in module file
|
|
#
|
|
@cached_property
|
|
def Specification(self):
|
|
return self.Module.Specification
|
|
|
|
## Tool option for the module build
|
|
#
|
|
# @param PlatformInfo The object of PlatformBuildInfo
|
|
# @retval dict The dict containing valid options
|
|
#
|
|
@cached_property
|
|
def BuildOption(self):
|
|
RetVal, self.BuildRuleOrder = self.PlatformInfo.ApplyBuildOption(self.Module)
|
|
if self.BuildRuleOrder:
|
|
self.BuildRuleOrder = ['.%s' % Ext for Ext in self.BuildRuleOrder.split()]
|
|
return RetVal
|
|
|
|
## Get include path list from tool option for the module build
|
|
#
|
|
# @retval list The include path list
|
|
#
|
|
@cached_property
|
|
def BuildOptionIncPathList(self):
|
|
#
|
|
# Regular expression for finding Include Directories, the difference between MSFT and INTEL/GCC/RVCT
|
|
# is the former use /I , the Latter used -I to specify include directories
|
|
#
|
|
if self.PlatformInfo.ToolChainFamily in (TAB_COMPILER_MSFT):
|
|
BuildOptIncludeRegEx = gBuildOptIncludePatternMsft
|
|
elif self.PlatformInfo.ToolChainFamily in ('INTEL', 'GCC', 'RVCT'):
|
|
BuildOptIncludeRegEx = gBuildOptIncludePatternOther
|
|
else:
|
|
#
|
|
# New ToolChainFamily, don't known whether there is option to specify include directories
|
|
#
|
|
return []
|
|
|
|
RetVal = []
|
|
for Tool in ('CC', 'PP', 'VFRPP', 'ASLPP', 'ASLCC', 'APP', 'ASM'):
|
|
try:
|
|
FlagOption = self.BuildOption[Tool]['FLAGS']
|
|
except KeyError:
|
|
FlagOption = ''
|
|
|
|
if self.ToolChainFamily != 'RVCT':
|
|
IncPathList = [NormPath(Path, self.Macros) for Path in BuildOptIncludeRegEx.findall(FlagOption)]
|
|
else:
|
|
#
|
|
# RVCT may specify a list of directory seperated by commas
|
|
#
|
|
IncPathList = []
|
|
for Path in BuildOptIncludeRegEx.findall(FlagOption):
|
|
PathList = GetSplitList(Path, TAB_COMMA_SPLIT)
|
|
IncPathList.extend(NormPath(PathEntry, self.Macros) for PathEntry in PathList)
|
|
|
|
#
|
|
# EDK II modules must not reference header files outside of the packages they depend on or
|
|
# within the module's directory tree. Report error if violation.
|
|
#
|
|
if GlobalData.gDisableIncludePathCheck == False:
|
|
for Path in IncPathList:
|
|
if (Path not in self.IncludePathList) and (CommonPath([Path, self.MetaFile.Dir]) != self.MetaFile.Dir):
|
|
ErrMsg = "The include directory for the EDK II module in this line is invalid %s specified in %s FLAGS '%s'" % (Path, Tool, FlagOption)
|
|
EdkLogger.error("build",
|
|
PARAMETER_INVALID,
|
|
ExtraData=ErrMsg,
|
|
File=str(self.MetaFile))
|
|
RetVal += IncPathList
|
|
return RetVal
|
|
|
|
## Return a list of files which can be built from source
|
|
#
|
|
# What kind of files can be built is determined by build rules in
|
|
# $(CONF_DIRECTORY)/build_rule.txt and toolchain family.
|
|
#
|
|
@cached_property
|
|
def SourceFileList(self):
|
|
RetVal = []
|
|
ToolChainTagSet = {"", TAB_STAR, self.ToolChain}
|
|
ToolChainFamilySet = {"", TAB_STAR, self.ToolChainFamily, self.BuildRuleFamily}
|
|
for F in self.Module.Sources:
|
|
# match tool chain
|
|
if F.TagName not in ToolChainTagSet:
|
|
EdkLogger.debug(EdkLogger.DEBUG_9, "The toolchain [%s] for processing file [%s] is found, "
|
|
"but [%s] is currently used" % (F.TagName, str(F), self.ToolChain))
|
|
continue
|
|
# match tool chain family or build rule family
|
|
if F.ToolChainFamily not in ToolChainFamilySet:
|
|
EdkLogger.debug(
|
|
EdkLogger.DEBUG_0,
|
|
"The file [%s] must be built by tools of [%s], " \
|
|
"but current toolchain family is [%s], buildrule family is [%s]" \
|
|
% (str(F), F.ToolChainFamily, self.ToolChainFamily, self.BuildRuleFamily))
|
|
continue
|
|
|
|
# add the file path into search path list for file including
|
|
if F.Dir not in self.IncludePathList:
|
|
self.IncludePathList.insert(0, F.Dir)
|
|
RetVal.append(F)
|
|
|
|
self._MatchBuildRuleOrder(RetVal)
|
|
|
|
for F in RetVal:
|
|
self._ApplyBuildRule(F, TAB_UNKNOWN_FILE)
|
|
return RetVal
|
|
|
|
def _MatchBuildRuleOrder(self, FileList):
|
|
Order_Dict = {}
|
|
self.BuildOption
|
|
for SingleFile in FileList:
|
|
if self.BuildRuleOrder and SingleFile.Ext in self.BuildRuleOrder and SingleFile.Ext in self.BuildRules:
|
|
key = SingleFile.Path.rsplit(SingleFile.Ext,1)[0]
|
|
if key in Order_Dict:
|
|
Order_Dict[key].append(SingleFile.Ext)
|
|
else:
|
|
Order_Dict[key] = [SingleFile.Ext]
|
|
|
|
RemoveList = []
|
|
for F in Order_Dict:
|
|
if len(Order_Dict[F]) > 1:
|
|
Order_Dict[F].sort(key=lambda i: self.BuildRuleOrder.index(i))
|
|
for Ext in Order_Dict[F][1:]:
|
|
RemoveList.append(F + Ext)
|
|
|
|
for item in RemoveList:
|
|
FileList.remove(item)
|
|
|
|
return FileList
|
|
|
|
## Return the list of unicode files
|
|
@cached_property
|
|
def UnicodeFileList(self):
|
|
return self.FileTypes.get(TAB_UNICODE_FILE,[])
|
|
|
|
## Return the list of vfr files
|
|
@cached_property
|
|
def VfrFileList(self):
|
|
return self.FileTypes.get(TAB_VFR_FILE, [])
|
|
|
|
## Return the list of Image Definition files
|
|
@cached_property
|
|
def IdfFileList(self):
|
|
return self.FileTypes.get(TAB_IMAGE_FILE,[])
|
|
|
|
## Return a list of files which can be built from binary
|
|
#
|
|
# "Build" binary files are just to copy them to build directory.
|
|
#
|
|
# @retval list The list of files which can be built later
|
|
#
|
|
@cached_property
|
|
def BinaryFileList(self):
|
|
RetVal = []
|
|
for F in self.Module.Binaries:
|
|
if F.Target not in [TAB_ARCH_COMMON, TAB_STAR] and F.Target != self.BuildTarget:
|
|
continue
|
|
RetVal.append(F)
|
|
self._ApplyBuildRule(F, F.Type, BinaryFileList=RetVal)
|
|
return RetVal
|
|
|
|
@cached_property
|
|
def BuildRules(self):
|
|
RetVal = {}
|
|
BuildRuleDatabase = self.PlatformInfo.BuildRule
|
|
for Type in BuildRuleDatabase.FileTypeList:
|
|
#first try getting build rule by BuildRuleFamily
|
|
RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.BuildRuleFamily]
|
|
if not RuleObject:
|
|
# build type is always module type, but ...
|
|
if self.ModuleType != self.BuildType:
|
|
RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.BuildRuleFamily]
|
|
#second try getting build rule by ToolChainFamily
|
|
if not RuleObject:
|
|
RuleObject = BuildRuleDatabase[Type, self.BuildType, self.Arch, self.ToolChainFamily]
|
|
if not RuleObject:
|
|
# build type is always module type, but ...
|
|
if self.ModuleType != self.BuildType:
|
|
RuleObject = BuildRuleDatabase[Type, self.ModuleType, self.Arch, self.ToolChainFamily]
|
|
if not RuleObject:
|
|
continue
|
|
RuleObject = RuleObject.Instantiate(self.Macros)
|
|
RetVal[Type] = RuleObject
|
|
for Ext in RuleObject.SourceFileExtList:
|
|
RetVal[Ext] = RuleObject
|
|
return RetVal
|
|
|
|
def _ApplyBuildRule(self, File, FileType, BinaryFileList=None):
|
|
if self._BuildTargets is None:
|
|
self._IntroBuildTargetList = set()
|
|
self._FinalBuildTargetList = set()
|
|
self._BuildTargets = defaultdict(set)
|
|
self._FileTypes = defaultdict(set)
|
|
|
|
if not BinaryFileList:
|
|
BinaryFileList = self.BinaryFileList
|
|
|
|
SubDirectory = os.path.join(self.OutputDir, File.SubDir)
|
|
if not os.path.exists(SubDirectory):
|
|
CreateDirectory(SubDirectory)
|
|
LastTarget = None
|
|
RuleChain = set()
|
|
SourceList = [File]
|
|
Index = 0
|
|
#
|
|
# Make sure to get build rule order value
|
|
#
|
|
self.BuildOption
|
|
|
|
while Index < len(SourceList):
|
|
Source = SourceList[Index]
|
|
Index = Index + 1
|
|
|
|
if Source != File:
|
|
CreateDirectory(Source.Dir)
|
|
|
|
if File.IsBinary and File == Source and File in BinaryFileList:
|
|
# Skip all files that are not binary libraries
|
|
if not self.IsLibrary:
|
|
continue
|
|
RuleObject = self.BuildRules[TAB_DEFAULT_BINARY_FILE]
|
|
elif FileType in self.BuildRules:
|
|
RuleObject = self.BuildRules[FileType]
|
|
elif Source.Ext in self.BuildRules:
|
|
RuleObject = self.BuildRules[Source.Ext]
|
|
else:
|
|
# stop at no more rules
|
|
if LastTarget:
|
|
self._FinalBuildTargetList.add(LastTarget)
|
|
break
|
|
|
|
FileType = RuleObject.SourceFileType
|
|
self._FileTypes[FileType].add(Source)
|
|
|
|
# stop at STATIC_LIBRARY for library
|
|
if self.IsLibrary and FileType == TAB_STATIC_LIBRARY:
|
|
if LastTarget:
|
|
self._FinalBuildTargetList.add(LastTarget)
|
|
break
|
|
|
|
Target = RuleObject.Apply(Source, self.BuildRuleOrder)
|
|
if not Target:
|
|
if LastTarget:
|
|
self._FinalBuildTargetList.add(LastTarget)
|
|
break
|
|
elif not Target.Outputs:
|
|
# Only do build for target with outputs
|
|
self._FinalBuildTargetList.add(Target)
|
|
|
|
self._BuildTargets[FileType].add(Target)
|
|
|
|
if not Source.IsBinary and Source == File:
|
|
self._IntroBuildTargetList.add(Target)
|
|
|
|
# to avoid cyclic rule
|
|
if FileType in RuleChain:
|
|
break
|
|
|
|
RuleChain.add(FileType)
|
|
SourceList.extend(Target.Outputs)
|
|
LastTarget = Target
|
|
FileType = TAB_UNKNOWN_FILE
|
|
|
|
@cached_property
|
|
def Targets(self):
|
|
if self._BuildTargets is None:
|
|
self._IntroBuildTargetList = set()
|
|
self._FinalBuildTargetList = set()
|
|
self._BuildTargets = defaultdict(set)
|
|
self._FileTypes = defaultdict(set)
|
|
|
|
#TRICK: call SourceFileList property to apply build rule for source files
|
|
self.SourceFileList
|
|
|
|
#TRICK: call _GetBinaryFileList to apply build rule for binary files
|
|
self.BinaryFileList
|
|
|
|
return self._BuildTargets
|
|
|
|
@cached_property
|
|
def IntroTargetList(self):
|
|
self.Targets
|
|
return self._IntroBuildTargetList
|
|
|
|
@cached_property
|
|
def CodaTargetList(self):
|
|
self.Targets
|
|
return self._FinalBuildTargetList
|
|
|
|
@cached_property
|
|
def FileTypes(self):
|
|
self.Targets
|
|
return self._FileTypes
|
|
|
|
## Get the list of package object the module depends on
|
|
#
|
|
# @retval list The package object list
|
|
#
|
|
@cached_property
|
|
def DependentPackageList(self):
|
|
return self.Module.Packages
|
|
|
|
## Return the list of auto-generated code file
|
|
#
|
|
# @retval list The list of auto-generated file
|
|
#
|
|
@cached_property
|
|
def AutoGenFileList(self):
|
|
AutoGenUniIdf = self.BuildType != 'UEFI_HII'
|
|
UniStringBinBuffer = BytesIO()
|
|
IdfGenBinBuffer = BytesIO()
|
|
RetVal = {}
|
|
AutoGenC = TemplateString()
|
|
AutoGenH = TemplateString()
|
|
StringH = TemplateString()
|
|
StringIdf = TemplateString()
|
|
GenC.CreateCode(self, AutoGenC, AutoGenH, StringH, AutoGenUniIdf, UniStringBinBuffer, StringIdf, AutoGenUniIdf, IdfGenBinBuffer)
|
|
#
|
|
# AutoGen.c is generated if there are library classes in inf, or there are object files
|
|
#
|
|
if str(AutoGenC) != "" and (len(self.Module.LibraryClasses) > 0
|
|
or TAB_OBJECT_FILE in self.FileTypes):
|
|
AutoFile = PathClass(gAutoGenCodeFileName, self.DebugDir)
|
|
RetVal[AutoFile] = str(AutoGenC)
|
|
self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
|
|
if str(AutoGenH) != "":
|
|
AutoFile = PathClass(gAutoGenHeaderFileName, self.DebugDir)
|
|
RetVal[AutoFile] = str(AutoGenH)
|
|
self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
|
|
if str(StringH) != "":
|
|
AutoFile = PathClass(gAutoGenStringFileName % {"module_name":self.Name}, self.DebugDir)
|
|
RetVal[AutoFile] = str(StringH)
|
|
self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
|
|
if UniStringBinBuffer is not None and UniStringBinBuffer.getvalue() != b"":
|
|
AutoFile = PathClass(gAutoGenStringFormFileName % {"module_name":self.Name}, self.OutputDir)
|
|
RetVal[AutoFile] = UniStringBinBuffer.getvalue()
|
|
AutoFile.IsBinary = True
|
|
self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
|
|
if UniStringBinBuffer is not None:
|
|
UniStringBinBuffer.close()
|
|
if str(StringIdf) != "":
|
|
AutoFile = PathClass(gAutoGenImageDefFileName % {"module_name":self.Name}, self.DebugDir)
|
|
RetVal[AutoFile] = str(StringIdf)
|
|
self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
|
|
if IdfGenBinBuffer is not None and IdfGenBinBuffer.getvalue() != b"":
|
|
AutoFile = PathClass(gAutoGenIdfFileName % {"module_name":self.Name}, self.OutputDir)
|
|
RetVal[AutoFile] = IdfGenBinBuffer.getvalue()
|
|
AutoFile.IsBinary = True
|
|
self._ApplyBuildRule(AutoFile, TAB_UNKNOWN_FILE)
|
|
if IdfGenBinBuffer is not None:
|
|
IdfGenBinBuffer.close()
|
|
return RetVal
|
|
|
|
## Return the list of library modules explicitly or implicitly used by this module
|
|
@cached_property
|
|
def DependentLibraryList(self):
|
|
# only merge library classes and PCD for non-library module
|
|
if self.IsLibrary:
|
|
return []
|
|
return self.PlatformInfo.ApplyLibraryInstance(self.Module)
|
|
|
|
## Get the list of PCDs from current module
|
|
#
|
|
# @retval list The list of PCD
|
|
#
|
|
@cached_property
|
|
def ModulePcdList(self):
|
|
# apply PCD settings from platform
|
|
RetVal = self.PlatformInfo.ApplyPcdSetting(self.Module, self.Module.Pcds)
|
|
|
|
return RetVal
|
|
@cached_property
|
|
def _PcdComments(self):
|
|
ReVal = OrderedListDict()
|
|
ExtendCopyDictionaryLists(ReVal, self.Module.PcdComments)
|
|
if not self.IsLibrary:
|
|
for Library in self.DependentLibraryList:
|
|
ExtendCopyDictionaryLists(ReVal, Library.PcdComments)
|
|
return ReVal
|
|
|
|
## Get the list of PCDs from dependent libraries
|
|
#
|
|
# @retval list The list of PCD
|
|
#
|
|
@cached_property
|
|
def LibraryPcdList(self):
|
|
if self.IsLibrary:
|
|
return []
|
|
RetVal = []
|
|
Pcds = set()
|
|
# get PCDs from dependent libraries
|
|
for Library in self.DependentLibraryList:
|
|
PcdsInLibrary = OrderedDict()
|
|
for Key in Library.Pcds:
|
|
# skip duplicated PCDs
|
|
if Key in self.Module.Pcds or Key in Pcds:
|
|
continue
|
|
Pcds.add(Key)
|
|
PcdsInLibrary[Key] = copy.copy(Library.Pcds[Key])
|
|
RetVal.extend(self.PlatformInfo.ApplyPcdSetting(self.Module, PcdsInLibrary, Library=Library))
|
|
return RetVal
|
|
|
|
## Get the GUID value mapping
|
|
#
|
|
# @retval dict The mapping between GUID cname and its value
|
|
#
|
|
@cached_property
|
|
def GuidList(self):
|
|
RetVal = self.Module.Guids
|
|
for Library in self.DependentLibraryList:
|
|
RetVal.update(Library.Guids)
|
|
ExtendCopyDictionaryLists(self._GuidComments, Library.GuidComments)
|
|
ExtendCopyDictionaryLists(self._GuidComments, self.Module.GuidComments)
|
|
return RetVal
|
|
|
|
@cached_property
|
|
def GetGuidsUsedByPcd(self):
|
|
RetVal = OrderedDict(self.Module.GetGuidsUsedByPcd())
|
|
for Library in self.DependentLibraryList:
|
|
RetVal.update(Library.GetGuidsUsedByPcd())
|
|
return RetVal
|
|
## Get the protocol value mapping
|
|
#
|
|
# @retval dict The mapping between protocol cname and its value
|
|
#
|
|
@cached_property
|
|
def ProtocolList(self):
|
|
RetVal = OrderedDict(self.Module.Protocols)
|
|
for Library in self.DependentLibraryList:
|
|
RetVal.update(Library.Protocols)
|
|
ExtendCopyDictionaryLists(self._ProtocolComments, Library.ProtocolComments)
|
|
ExtendCopyDictionaryLists(self._ProtocolComments, self.Module.ProtocolComments)
|
|
return RetVal
|
|
|
|
## Get the PPI value mapping
|
|
#
|
|
# @retval dict The mapping between PPI cname and its value
|
|
#
|
|
@cached_property
|
|
def PpiList(self):
|
|
RetVal = OrderedDict(self.Module.Ppis)
|
|
for Library in self.DependentLibraryList:
|
|
RetVal.update(Library.Ppis)
|
|
ExtendCopyDictionaryLists(self._PpiComments, Library.PpiComments)
|
|
ExtendCopyDictionaryLists(self._PpiComments, self.Module.PpiComments)
|
|
return RetVal
|
|
|
|
## Get the list of include search path
|
|
#
|
|
# @retval list The list path
|
|
#
|
|
@cached_property
|
|
def IncludePathList(self):
|
|
RetVal = []
|
|
RetVal.append(self.MetaFile.Dir)
|
|
RetVal.append(self.DebugDir)
|
|
|
|
for Package in self.Module.Packages:
|
|
PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)
|
|
if PackageDir not in RetVal:
|
|
RetVal.append(PackageDir)
|
|
IncludesList = Package.Includes
|
|
if Package._PrivateIncludes:
|
|
if not self.MetaFile.OriginalPath.Path.startswith(PackageDir):
|
|
IncludesList = list(set(Package.Includes).difference(set(Package._PrivateIncludes)))
|
|
for Inc in IncludesList:
|
|
if Inc not in RetVal:
|
|
RetVal.append(str(Inc))
|
|
return RetVal
|
|
|
|
@cached_property
|
|
def IncludePathLength(self):
|
|
return sum(len(inc)+1 for inc in self.IncludePathList)
|
|
|
|
## Get the list of include paths from the packages
|
|
#
|
|
# @IncludesList list The list path
|
|
#
|
|
@cached_property
|
|
def PackageIncludePathList(self):
|
|
IncludesList = []
|
|
for Package in self.Module.Packages:
|
|
PackageDir = mws.join(self.WorkspaceDir, Package.MetaFile.Dir)
|
|
IncludesList = Package.Includes
|
|
if Package._PrivateIncludes:
|
|
if not self.MetaFile.Path.startswith(PackageDir):
|
|
IncludesList = list(set(Package.Includes).difference(set(Package._PrivateIncludes)))
|
|
return IncludesList
|
|
|
|
## Get HII EX PCDs which maybe used by VFR
|
|
#
|
|
# efivarstore used by VFR may relate with HII EX PCDs
|
|
# Get the variable name and GUID from efivarstore and HII EX PCD
|
|
# List the HII EX PCDs in As Built INF if both name and GUID match.
|
|
#
|
|
# @retval list HII EX PCDs
|
|
#
|
|
def _GetPcdsMaybeUsedByVfr(self):
|
|
if not self.SourceFileList:
|
|
return []
|
|
|
|
NameGuids = set()
|
|
for SrcFile in self.SourceFileList:
|
|
if SrcFile.Ext.lower() != '.vfr':
|
|
continue
|
|
Vfri = os.path.join(self.OutputDir, SrcFile.BaseName + '.i')
|
|
if not os.path.exists(Vfri):
|
|
continue
|
|
VfriFile = open(Vfri, 'r')
|
|
Content = VfriFile.read()
|
|
VfriFile.close()
|
|
Pos = Content.find('efivarstore')
|
|
while Pos != -1:
|
|
#
|
|
# Make sure 'efivarstore' is the start of efivarstore statement
|
|
# In case of the value of 'name' (name = efivarstore) is equal to 'efivarstore'
|
|
#
|
|
Index = Pos - 1
|
|
while Index >= 0 and Content[Index] in ' \t\r\n':
|
|
Index -= 1
|
|
if Index >= 0 and Content[Index] != ';':
|
|
Pos = Content.find('efivarstore', Pos + len('efivarstore'))
|
|
continue
|
|
#
|
|
# 'efivarstore' must be followed by name and guid
|
|
#
|
|
Name = gEfiVarStoreNamePattern.search(Content, Pos)
|
|
if not Name:
|
|
break
|
|
Guid = gEfiVarStoreGuidPattern.search(Content, Pos)
|
|
if not Guid:
|
|
break
|
|
NameArray = _ConvertStringToByteArray('L"' + Name.group(1) + '"')
|
|
NameGuids.add((NameArray, GuidStructureStringToGuidString(Guid.group(1))))
|
|
Pos = Content.find('efivarstore', Name.end())
|
|
if not NameGuids:
|
|
return []
|
|
HiiExPcds = []
|
|
for Pcd in self.PlatformInfo.Pcds.values():
|
|
if Pcd.Type != TAB_PCDS_DYNAMIC_EX_HII:
|
|
continue
|
|
for SkuInfo in Pcd.SkuInfoList.values():
|
|
Value = GuidValue(SkuInfo.VariableGuid, self.PlatformInfo.PackageList, self.MetaFile.Path)
|
|
if not Value:
|
|
continue
|
|
Name = _ConvertStringToByteArray(SkuInfo.VariableName)
|
|
Guid = GuidStructureStringToGuidString(Value)
|
|
if (Name, Guid) in NameGuids and Pcd not in HiiExPcds:
|
|
HiiExPcds.append(Pcd)
|
|
break
|
|
|
|
return HiiExPcds
|
|
|
|
def _GenOffsetBin(self):
|
|
VfrUniBaseName = {}
|
|
for SourceFile in self.Module.Sources:
|
|
if SourceFile.Type.upper() == ".VFR" :
|
|
#
|
|
# search the .map file to find the offset of vfr binary in the PE32+/TE file.
|
|
#
|
|
VfrUniBaseName[SourceFile.BaseName] = (SourceFile.BaseName + "Bin")
|
|
elif SourceFile.Type.upper() == ".UNI" :
|
|
#
|
|
# search the .map file to find the offset of Uni strings binary in the PE32+/TE file.
|
|
#
|
|
VfrUniBaseName["UniOffsetName"] = (self.Name + "Strings")
|
|
|
|
if not VfrUniBaseName:
|
|
return None
|
|
MapFileName = os.path.join(self.OutputDir, self.Name + ".map")
|
|
EfiFileName = os.path.join(self.OutputDir, self.Name + ".efi")
|
|
VfrUniOffsetList = GetVariableOffset(MapFileName, EfiFileName, list(VfrUniBaseName.values()))
|
|
if not VfrUniOffsetList:
|
|
return None
|
|
|
|
OutputName = '%sOffset.bin' % self.Name
|
|
UniVfrOffsetFileName = os.path.join( self.OutputDir, OutputName)
|
|
|
|
try:
|
|
fInputfile = open(UniVfrOffsetFileName, "wb+", 0)
|
|
except:
|
|
EdkLogger.error("build", FILE_OPEN_FAILURE, "File open failed for %s" % UniVfrOffsetFileName, None)
|
|
|
|
# Use a instance of BytesIO to cache data
|
|
fStringIO = BytesIO()
|
|
|
|
for Item in VfrUniOffsetList:
|
|
if (Item[0].find("Strings") != -1):
|
|
#
|
|
# UNI offset in image.
|
|
# GUID + Offset
|
|
# { 0x8913c5e0, 0x33f6, 0x4d86, { 0x9b, 0xf1, 0x43, 0xef, 0x89, 0xfc, 0x6, 0x66 } }
|
|
#
|
|
UniGuid = b'\xe0\xc5\x13\x89\xf63\x86M\x9b\xf1C\xef\x89\xfc\x06f'
|
|
fStringIO.write(UniGuid)
|
|
UniValue = pack ('Q', int (Item[1], 16))
|
|
fStringIO.write (UniValue)
|
|
else:
|
|
#
|
|
# VFR binary offset in image.
|
|
# GUID + Offset
|
|
# { 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } };
|
|
#
|
|
VfrGuid = b'\xb4|\xbc\xd0Gj_I\xaa\x11q\x07F\xda\x06\xa2'
|
|
fStringIO.write(VfrGuid)
|
|
VfrValue = pack ('Q', int (Item[1], 16))
|
|
fStringIO.write (VfrValue)
|
|
#
|
|
# write data into file.
|
|
#
|
|
try :
|
|
fInputfile.write (fStringIO.getvalue())
|
|
except:
|
|
EdkLogger.error("build", FILE_WRITE_FAILURE, "Write data to file %s failed, please check whether the "
|
|
"file been locked or using by other applications." %UniVfrOffsetFileName, None)
|
|
|
|
fStringIO.close ()
|
|
fInputfile.close ()
|
|
return OutputName
|
|
|
|
@cached_property
|
|
def OutputFile(self):
|
|
retVal = set()
|
|
|
|
OutputDir = self.OutputDir.replace('\\', '/').strip('/')
|
|
DebugDir = self.DebugDir.replace('\\', '/').strip('/')
|
|
for Item in self.CodaTargetList:
|
|
File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')
|
|
NewFile = path.join(self.OutputDir, File)
|
|
retVal.add(NewFile)
|
|
|
|
Bin = self._GenOffsetBin()
|
|
if Bin:
|
|
NewFile = path.join(self.OutputDir, Bin)
|
|
retVal.add(NewFile)
|
|
|
|
for Root, Dirs, Files in os.walk(self.OutputDir):
|
|
for File in Files:
|
|
# lib file is already added through above CodaTargetList, skip it here
|
|
if not (File.lower().endswith('.obj') or File.lower().endswith('.lib')):
|
|
NewFile = path.join(self.OutputDir, File)
|
|
retVal.add(NewFile)
|
|
|
|
for Root, Dirs, Files in os.walk(self.FfsOutputDir):
|
|
for File in Files:
|
|
NewFile = path.join(self.FfsOutputDir, File)
|
|
retVal.add(NewFile)
|
|
|
|
return retVal
|
|
|
|
## Create AsBuilt INF file the module
|
|
#
|
|
def CreateAsBuiltInf(self):
|
|
|
|
if self.IsAsBuiltInfCreated:
|
|
return
|
|
|
|
# Skip INF file generation for libraries
|
|
if self.IsLibrary:
|
|
return
|
|
|
|
# Skip the following code for modules with no source files
|
|
if not self.SourceFileList:
|
|
return
|
|
|
|
# Skip the following code for modules without any binary files
|
|
if self.BinaryFileList:
|
|
return
|
|
|
|
### TODO: How to handles mixed source and binary modules
|
|
|
|
# Find all DynamicEx and PatchableInModule PCDs used by this module and dependent libraries
|
|
# Also find all packages that the DynamicEx PCDs depend on
|
|
Pcds = []
|
|
PatchablePcds = []
|
|
Packages = []
|
|
PcdCheckList = []
|
|
PcdTokenSpaceList = []
|
|
for Pcd in self.ModulePcdList + self.LibraryPcdList:
|
|
if Pcd.Type == TAB_PCDS_PATCHABLE_IN_MODULE:
|
|
PatchablePcds.append(Pcd)
|
|
PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_PATCHABLE_IN_MODULE))
|
|
elif Pcd.Type in PCD_DYNAMIC_EX_TYPE_SET:
|
|
if Pcd not in Pcds:
|
|
Pcds.append(Pcd)
|
|
PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX))
|
|
PcdCheckList.append((Pcd.TokenCName, Pcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC))
|
|
PcdTokenSpaceList.append(Pcd.TokenSpaceGuidCName)
|
|
GuidList = OrderedDict(self.GuidList)
|
|
for TokenSpace in self.GetGuidsUsedByPcd:
|
|
# If token space is not referred by patch PCD or Ex PCD, remove the GUID from GUID list
|
|
# The GUIDs in GUIDs section should really be the GUIDs in source INF or referred by Ex an patch PCDs
|
|
if TokenSpace not in PcdTokenSpaceList and TokenSpace in GuidList:
|
|
GuidList.pop(TokenSpace)
|
|
CheckList = (GuidList, self.PpiList, self.ProtocolList, PcdCheckList)
|
|
for Package in self.DerivedPackageList:
|
|
if Package in Packages:
|
|
continue
|
|
BeChecked = (Package.Guids, Package.Ppis, Package.Protocols, Package.Pcds)
|
|
Found = False
|
|
for Index in range(len(BeChecked)):
|
|
for Item in CheckList[Index]:
|
|
if Item in BeChecked[Index]:
|
|
Packages.append(Package)
|
|
Found = True
|
|
break
|
|
if Found:
|
|
break
|
|
|
|
VfrPcds = self._GetPcdsMaybeUsedByVfr()
|
|
for Pkg in self.PlatformInfo.PackageList:
|
|
if Pkg in Packages:
|
|
continue
|
|
for VfrPcd in VfrPcds:
|
|
if ((VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC_EX) in Pkg.Pcds or
|
|
(VfrPcd.TokenCName, VfrPcd.TokenSpaceGuidCName, TAB_PCDS_DYNAMIC) in Pkg.Pcds):
|
|
Packages.append(Pkg)
|
|
break
|
|
|
|
ModuleType = SUP_MODULE_DXE_DRIVER if self.ModuleType == SUP_MODULE_UEFI_DRIVER and self.DepexGenerated else self.ModuleType
|
|
DriverType = self.PcdIsDriver if self.PcdIsDriver else ''
|
|
Guid = self.Guid
|
|
MDefs = self.Module.Defines
|
|
|
|
AsBuiltInfDict = {
|
|
'module_name' : self.Name,
|
|
'module_guid' : Guid,
|
|
'module_module_type' : ModuleType,
|
|
'module_version_string' : [MDefs['VERSION_STRING']] if 'VERSION_STRING' in MDefs else [],
|
|
'pcd_is_driver_string' : [],
|
|
'module_uefi_specification_version' : [],
|
|
'module_pi_specification_version' : [],
|
|
'module_entry_point' : self.Module.ModuleEntryPointList,
|
|
'module_unload_image' : self.Module.ModuleUnloadImageList,
|
|
'module_constructor' : self.Module.ConstructorList,
|
|
'module_destructor' : self.Module.DestructorList,
|
|
'module_shadow' : [MDefs['SHADOW']] if 'SHADOW' in MDefs else [],
|
|
'module_pci_vendor_id' : [MDefs['PCI_VENDOR_ID']] if 'PCI_VENDOR_ID' in MDefs else [],
|
|
'module_pci_device_id' : [MDefs['PCI_DEVICE_ID']] if 'PCI_DEVICE_ID' in MDefs else [],
|
|
'module_pci_class_code' : [MDefs['PCI_CLASS_CODE']] if 'PCI_CLASS_CODE' in MDefs else [],
|
|
'module_pci_revision' : [MDefs['PCI_REVISION']] if 'PCI_REVISION' in MDefs else [],
|
|
'module_build_number' : [MDefs['BUILD_NUMBER']] if 'BUILD_NUMBER' in MDefs else [],
|
|
'module_spec' : [MDefs['SPEC']] if 'SPEC' in MDefs else [],
|
|
'module_uefi_hii_resource_section' : [MDefs['UEFI_HII_RESOURCE_SECTION']] if 'UEFI_HII_RESOURCE_SECTION' in MDefs else [],
|
|
'module_uni_file' : [MDefs['MODULE_UNI_FILE']] if 'MODULE_UNI_FILE' in MDefs else [],
|
|
'module_arch' : self.Arch,
|
|
'package_item' : [Package.MetaFile.File.replace('\\', '/') for Package in Packages],
|
|
'binary_item' : [],
|
|
'patchablepcd_item' : [],
|
|
'pcd_item' : [],
|
|
'protocol_item' : [],
|
|
'ppi_item' : [],
|
|
'guid_item' : [],
|
|
'flags_item' : [],
|
|
'libraryclasses_item' : []
|
|
}
|
|
|
|
if 'MODULE_UNI_FILE' in MDefs:
|
|
UNIFile = os.path.join(self.MetaFile.Dir, MDefs['MODULE_UNI_FILE'])
|
|
if os.path.isfile(UNIFile):
|
|
shutil.copy2(UNIFile, self.OutputDir)
|
|
|
|
if self.AutoGenVersion > int(gInfSpecVersion, 0):
|
|
AsBuiltInfDict['module_inf_version'] = '0x%08x' % self.AutoGenVersion
|
|
else:
|
|
AsBuiltInfDict['module_inf_version'] = gInfSpecVersion
|
|
|
|
if DriverType:
|
|
AsBuiltInfDict['pcd_is_driver_string'].append(DriverType)
|
|
|
|
if 'UEFI_SPECIFICATION_VERSION' in self.Specification:
|
|
AsBuiltInfDict['module_uefi_specification_version'].append(self.Specification['UEFI_SPECIFICATION_VERSION'])
|
|
if 'PI_SPECIFICATION_VERSION' in self.Specification:
|
|
AsBuiltInfDict['module_pi_specification_version'].append(self.Specification['PI_SPECIFICATION_VERSION'])
|
|
|
|
OutputDir = self.OutputDir.replace('\\', '/').strip('/')
|
|
DebugDir = self.DebugDir.replace('\\', '/').strip('/')
|
|
for Item in self.CodaTargetList:
|
|
File = Item.Target.Path.replace('\\', '/').strip('/').replace(DebugDir, '').replace(OutputDir, '').strip('/')
|
|
if os.path.isabs(File):
|
|
File = File.replace('\\', '/').strip('/').replace(OutputDir, '').strip('/')
|
|
if Item.Target.Ext.lower() == '.aml':
|
|
AsBuiltInfDict['binary_item'].append('ASL|' + File)
|
|
elif Item.Target.Ext.lower() == '.acpi':
|
|
AsBuiltInfDict['binary_item'].append('ACPI|' + File)
|
|
elif Item.Target.Ext.lower() == '.efi':
|
|
AsBuiltInfDict['binary_item'].append('PE32|' + self.Name + '.efi')
|
|
else:
|
|
AsBuiltInfDict['binary_item'].append('BIN|' + File)
|
|
if not self.DepexGenerated:
|
|
DepexFile = os.path.join(self.OutputDir, self.Name + '.depex')
|
|
if os.path.exists(DepexFile):
|
|
self.DepexGenerated = True
|
|
if self.DepexGenerated:
|
|
if self.ModuleType in [SUP_MODULE_PEIM]:
|
|
AsBuiltInfDict['binary_item'].append('PEI_DEPEX|' + self.Name + '.depex')
|
|
elif self.ModuleType in [SUP_MODULE_DXE_DRIVER, SUP_MODULE_DXE_RUNTIME_DRIVER, SUP_MODULE_DXE_SAL_DRIVER, SUP_MODULE_UEFI_DRIVER]:
|
|
AsBuiltInfDict['binary_item'].append('DXE_DEPEX|' + self.Name + '.depex')
|
|
elif self.ModuleType in [SUP_MODULE_DXE_SMM_DRIVER]:
|
|
AsBuiltInfDict['binary_item'].append('SMM_DEPEX|' + self.Name + '.depex')
|
|
|
|
Bin = self._GenOffsetBin()
|
|
if Bin:
|
|
AsBuiltInfDict['binary_item'].append('BIN|%s' % Bin)
|
|
|
|
for Root, Dirs, Files in os.walk(OutputDir):
|
|
for File in Files:
|
|
if File.lower().endswith('.pdb'):
|
|
AsBuiltInfDict['binary_item'].append('DISPOSABLE|' + File)
|
|
HeaderComments = self.Module.HeaderComments
|
|
StartPos = 0
|
|
for Index in range(len(HeaderComments)):
|
|
if HeaderComments[Index].find('@BinaryHeader') != -1:
|
|
HeaderComments[Index] = HeaderComments[Index].replace('@BinaryHeader', '@file')
|
|
StartPos = Index
|
|
break
|
|
AsBuiltInfDict['header_comments'] = '\n'.join(HeaderComments[StartPos:]).replace(':#', '://')
|
|
AsBuiltInfDict['tail_comments'] = '\n'.join(self.Module.TailComments)
|
|
|
|
GenList = [
|
|
(self.ProtocolList, self._ProtocolComments, 'protocol_item'),
|
|
(self.PpiList, self._PpiComments, 'ppi_item'),
|
|
(GuidList, self._GuidComments, 'guid_item')
|
|
]
|
|
for Item in GenList:
|
|
for CName in Item[0]:
|
|
Comments = '\n '.join(Item[1][CName]) if CName in Item[1] else ''
|
|
Entry = Comments + '\n ' + CName if Comments else CName
|
|
AsBuiltInfDict[Item[2]].append(Entry)
|
|
PatchList = parsePcdInfoFromMapFile(
|
|
os.path.join(self.OutputDir, self.Name + '.map'),
|
|
os.path.join(self.OutputDir, self.Name + '.efi')
|
|
)
|
|
if PatchList:
|
|
for Pcd in PatchablePcds:
|
|
TokenCName = Pcd.TokenCName
|
|
for PcdItem in GlobalData.MixedPcd:
|
|
if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
|
|
TokenCName = PcdItem[0]
|
|
break
|
|
for PatchPcd in PatchList:
|
|
if TokenCName == PatchPcd[0]:
|
|
break
|
|
else:
|
|
continue
|
|
PcdValue = ''
|
|
if Pcd.DatumType == 'BOOLEAN':
|
|
BoolValue = Pcd.DefaultValue.upper()
|
|
if BoolValue == 'TRUE':
|
|
Pcd.DefaultValue = '1'
|
|
elif BoolValue == 'FALSE':
|
|
Pcd.DefaultValue = '0'
|
|
|
|
if Pcd.DatumType in TAB_PCD_NUMERIC_TYPES:
|
|
HexFormat = '0x%02x'
|
|
if Pcd.DatumType == TAB_UINT16:
|
|
HexFormat = '0x%04x'
|
|
elif Pcd.DatumType == TAB_UINT32:
|
|
HexFormat = '0x%08x'
|
|
elif Pcd.DatumType == TAB_UINT64:
|
|
HexFormat = '0x%016x'
|
|
PcdValue = HexFormat % int(Pcd.DefaultValue, 0)
|
|
else:
|
|
if Pcd.MaxDatumSize is None or Pcd.MaxDatumSize == '':
|
|
EdkLogger.error("build", AUTOGEN_ERROR,
|
|
"Unknown [MaxDatumSize] of PCD [%s.%s]" % (Pcd.TokenSpaceGuidCName, TokenCName)
|
|
)
|
|
ArraySize = int(Pcd.MaxDatumSize, 0)
|
|
PcdValue = Pcd.DefaultValue
|
|
if PcdValue[0] != '{':
|
|
Unicode = False
|
|
if PcdValue[0] == 'L':
|
|
Unicode = True
|
|
PcdValue = PcdValue.lstrip('L')
|
|
PcdValue = eval(PcdValue)
|
|
NewValue = '{'
|
|
for Index in range(0, len(PcdValue)):
|
|
if Unicode:
|
|
CharVal = ord(PcdValue[Index])
|
|
NewValue = NewValue + '0x%02x' % (CharVal & 0x00FF) + ', ' \
|
|
+ '0x%02x' % (CharVal >> 8) + ', '
|
|
else:
|
|
NewValue = NewValue + '0x%02x' % (ord(PcdValue[Index]) % 0x100) + ', '
|
|
Padding = '0x00, '
|
|
if Unicode:
|
|
Padding = Padding * 2
|
|
ArraySize = ArraySize // 2
|
|
if ArraySize < (len(PcdValue) + 1):
|
|
if Pcd.MaxSizeUserSet:
|
|
EdkLogger.error("build", AUTOGEN_ERROR,
|
|
"The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
|
|
)
|
|
else:
|
|
ArraySize = len(PcdValue) + 1
|
|
if ArraySize > len(PcdValue) + 1:
|
|
NewValue = NewValue + Padding * (ArraySize - len(PcdValue) - 1)
|
|
PcdValue = NewValue + Padding.strip().rstrip(',') + '}'
|
|
elif len(PcdValue.split(',')) <= ArraySize:
|
|
PcdValue = PcdValue.rstrip('}') + ', 0x00' * (ArraySize - len(PcdValue.split(',')))
|
|
PcdValue += '}'
|
|
else:
|
|
if Pcd.MaxSizeUserSet:
|
|
EdkLogger.error("build", AUTOGEN_ERROR,
|
|
"The maximum size of VOID* type PCD '%s.%s' is less than its actual size occupied." % (Pcd.TokenSpaceGuidCName, TokenCName)
|
|
)
|
|
else:
|
|
ArraySize = len(PcdValue) + 1
|
|
PcdItem = '%s.%s|%s|0x%X' % \
|
|
(Pcd.TokenSpaceGuidCName, TokenCName, PcdValue, PatchPcd[1])
|
|
PcdComments = ''
|
|
if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
|
|
PcdComments = '\n '.join(self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName])
|
|
if PcdComments:
|
|
PcdItem = PcdComments + '\n ' + PcdItem
|
|
AsBuiltInfDict['patchablepcd_item'].append(PcdItem)
|
|
|
|
for Pcd in Pcds + VfrPcds:
|
|
PcdCommentList = []
|
|
HiiInfo = ''
|
|
TokenCName = Pcd.TokenCName
|
|
for PcdItem in GlobalData.MixedPcd:
|
|
if (Pcd.TokenCName, Pcd.TokenSpaceGuidCName) in GlobalData.MixedPcd[PcdItem]:
|
|
TokenCName = PcdItem[0]
|
|
break
|
|
if Pcd.Type == TAB_PCDS_DYNAMIC_EX_HII:
|
|
for SkuName in Pcd.SkuInfoList:
|
|
SkuInfo = Pcd.SkuInfoList[SkuName]
|
|
HiiInfo = '## %s|%s|%s' % (SkuInfo.VariableName, SkuInfo.VariableGuid, SkuInfo.VariableOffset)
|
|
break
|
|
if (Pcd.TokenSpaceGuidCName, Pcd.TokenCName) in self._PcdComments:
|
|
PcdCommentList = self._PcdComments[Pcd.TokenSpaceGuidCName, Pcd.TokenCName][:]
|
|
if HiiInfo:
|
|
UsageIndex = -1
|
|
UsageStr = ''
|
|
for Index, Comment in enumerate(PcdCommentList):
|
|
for Usage in UsageList:
|
|
if Comment.find(Usage) != -1:
|
|
UsageStr = Usage
|
|
UsageIndex = Index
|
|
break
|
|
if UsageIndex != -1:
|
|
PcdCommentList[UsageIndex] = '## %s %s %s' % (UsageStr, HiiInfo, PcdCommentList[UsageIndex].replace(UsageStr, ''))
|
|
else:
|
|
PcdCommentList.append('## UNDEFINED ' + HiiInfo)
|
|
PcdComments = '\n '.join(PcdCommentList)
|
|
PcdEntry = Pcd.TokenSpaceGuidCName + '.' + TokenCName
|
|
if PcdComments:
|
|
PcdEntry = PcdComments + '\n ' + PcdEntry
|
|
AsBuiltInfDict['pcd_item'].append(PcdEntry)
|
|
for Item in self.BuildOption:
|
|
if 'FLAGS' in self.BuildOption[Item]:
|
|
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()))
|
|
|
|
# Generated LibraryClasses section in comments.
|
|
for Library in self.LibraryAutoGenList:
|
|
AsBuiltInfDict['libraryclasses_item'].append(Library.MetaFile.File.replace('\\', '/'))
|
|
|
|
# Generated UserExtensions TianoCore section.
|
|
# All tianocore user extensions are copied.
|
|
UserExtStr = ''
|
|
for TianoCore in self._GetTianoCoreUserExtensionList():
|
|
UserExtStr += '\n'.join(TianoCore)
|
|
ExtensionFile = os.path.join(self.MetaFile.Dir, TianoCore[1])
|
|
if os.path.isfile(ExtensionFile):
|
|
shutil.copy2(ExtensionFile, self.OutputDir)
|
|
AsBuiltInfDict['userextension_tianocore_item'] = UserExtStr
|
|
|
|
# Generated depex expression section in comments.
|
|
DepexExpression = self._GetDepexExpresionString()
|
|
AsBuiltInfDict['depexsection_item'] = DepexExpression if DepexExpression else ''
|
|
|
|
AsBuiltInf = TemplateString()
|
|
AsBuiltInf.Append(gAsBuiltInfHeaderString.Replace(AsBuiltInfDict))
|
|
|
|
SaveFileOnChange(os.path.join(self.OutputDir, self.Name + '.inf'), str(AsBuiltInf), False)
|
|
|
|
self.IsAsBuiltInfCreated = True
|
|
|
|
def CacheCopyFile(self, OriginDir, CopyDir, File):
|
|
sub_dir = os.path.relpath(File, CopyDir)
|
|
destination_file = os.path.join(OriginDir, sub_dir)
|
|
destination_dir = os.path.dirname(destination_file)
|
|
CreateDirectory(destination_dir)
|
|
try:
|
|
CopyFileOnChange(File, destination_dir)
|
|
except:
|
|
EdkLogger.quiet("[cache warning]: fail to copy file:%s to folder:%s" % (File, destination_dir))
|
|
return
|
|
|
|
def CopyModuleToCache(self):
|
|
self.GenPreMakefileHash(GlobalData.gCacheIR)
|
|
if not (self.MetaFile.Path, self.Arch) in GlobalData.gCacheIR or \
|
|
not GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest:
|
|
EdkLogger.quiet("[cache warning]: Cannot generate PreMakefileHash for module: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return False
|
|
|
|
self.GenMakeHash(GlobalData.gCacheIR)
|
|
if not (self.MetaFile.Path, self.Arch) in GlobalData.gCacheIR or \
|
|
not GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashChain or \
|
|
not GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest:
|
|
EdkLogger.quiet("[cache warning]: Cannot generate MakeHashChain for module: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return False
|
|
|
|
MakeHashStr = str(GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest)
|
|
FileDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName, MakeHashStr)
|
|
FfsDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name, MakeHashStr)
|
|
|
|
CreateDirectory (FileDir)
|
|
self.SaveHashChainFileToCache(GlobalData.gCacheIR)
|
|
ModuleFile = path.join(self.OutputDir, self.Name + '.inf')
|
|
if os.path.exists(ModuleFile):
|
|
CopyFileOnChange(ModuleFile, FileDir)
|
|
if not self.OutputFile:
|
|
Ma = self.BuildDatabase[self.MetaFile, self.Arch, self.BuildTarget, self.ToolChain]
|
|
self.OutputFile = Ma.Binaries
|
|
for File in self.OutputFile:
|
|
if os.path.exists(File):
|
|
if File.startswith(os.path.abspath(self.FfsOutputDir)+os.sep):
|
|
self.CacheCopyFile(FfsDir, self.FfsOutputDir, File)
|
|
else:
|
|
self.CacheCopyFile(FileDir, self.OutputDir, File)
|
|
|
|
def SaveHashChainFileToCache(self, gDict):
|
|
if not GlobalData.gBinCacheDest:
|
|
return False
|
|
|
|
self.GenPreMakefileHash(gDict)
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest:
|
|
EdkLogger.quiet("[cache warning]: Cannot generate PreMakefileHash for module: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return False
|
|
|
|
self.GenMakeHash(gDict)
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest:
|
|
EdkLogger.quiet("[cache warning]: Cannot generate MakeHashChain for module: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return False
|
|
|
|
# save the hash chain list as cache file
|
|
MakeHashStr = str(GlobalData.gCacheIR[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest)
|
|
CacheDestDir = path.join(GlobalData.gBinCacheDest, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)
|
|
CacheHashDestDir = path.join(CacheDestDir, MakeHashStr)
|
|
ModuleHashPair = path.join(CacheDestDir, self.Name + ".ModuleHashPair")
|
|
MakeHashChain = path.join(CacheHashDestDir, self.Name + ".MakeHashChain")
|
|
ModuleFilesChain = path.join(CacheHashDestDir, self.Name + ".ModuleFilesChain")
|
|
|
|
# save the HashChainDict as json file
|
|
CreateDirectory (CacheDestDir)
|
|
CreateDirectory (CacheHashDestDir)
|
|
try:
|
|
ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)]
|
|
if os.path.exists(ModuleHashPair):
|
|
with open(ModuleHashPair, 'r') as f:
|
|
ModuleHashPairList = json.load(f)
|
|
PreMakeHash = gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest
|
|
MakeHash = gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest
|
|
ModuleHashPairList.append((PreMakeHash, MakeHash))
|
|
ModuleHashPairList = list(set(map(tuple, ModuleHashPairList)))
|
|
with open(ModuleHashPair, 'w') as f:
|
|
json.dump(ModuleHashPairList, f, indent=2)
|
|
except:
|
|
EdkLogger.quiet("[cache warning]: fail to save ModuleHashPair file in cache: %s" % ModuleHashPair)
|
|
return False
|
|
|
|
try:
|
|
with open(MakeHashChain, 'w') as f:
|
|
json.dump(gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain, f, indent=2)
|
|
except:
|
|
EdkLogger.quiet("[cache warning]: fail to save MakeHashChain file in cache: %s" % MakeHashChain)
|
|
return False
|
|
|
|
try:
|
|
with open(ModuleFilesChain, 'w') as f:
|
|
json.dump(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain, f, indent=2)
|
|
except:
|
|
EdkLogger.quiet("[cache warning]: fail to save ModuleFilesChain file in cache: %s" % ModuleFilesChain)
|
|
return False
|
|
|
|
# save the autogenfile and makefile for debug usage
|
|
CacheDebugDir = path.join(CacheHashDestDir, "CacheDebug")
|
|
CreateDirectory (CacheDebugDir)
|
|
CopyFileOnChange(gDict[(self.MetaFile.Path, self.Arch)].MakefilePath, CacheDebugDir)
|
|
if gDict[(self.MetaFile.Path, self.Arch)].AutoGenFileList:
|
|
for File in gDict[(self.MetaFile.Path, self.Arch)].AutoGenFileList:
|
|
CopyFileOnChange(str(File), CacheDebugDir)
|
|
|
|
return True
|
|
|
|
## Create makefile for the module and its dependent libraries
|
|
#
|
|
# @param CreateLibraryMakeFile Flag indicating if or not the makefiles of
|
|
# dependent libraries will be created
|
|
#
|
|
@cached_class_function
|
|
def CreateMakeFile(self, CreateLibraryMakeFile=True, GenFfsList = []):
|
|
gDict = GlobalData.gCacheIR
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].CreateMakeFileDone:
|
|
return
|
|
|
|
# nest this function inside it's only caller.
|
|
def CreateTimeStamp():
|
|
FileSet = {self.MetaFile.Path}
|
|
|
|
for SourceFile in self.Module.Sources:
|
|
FileSet.add (SourceFile.Path)
|
|
|
|
for Lib in self.DependentLibraryList:
|
|
FileSet.add (Lib.MetaFile.Path)
|
|
|
|
for f in self.AutoGenDepSet:
|
|
FileSet.add (f.Path)
|
|
|
|
if os.path.exists (self.TimeStampPath):
|
|
os.remove (self.TimeStampPath)
|
|
|
|
SaveFileOnChange(self.TimeStampPath, "\n".join(FileSet), False)
|
|
|
|
# Ignore generating makefile when it is a binary module
|
|
if self.IsBinaryModule:
|
|
return
|
|
|
|
self.GenFfsList = GenFfsList
|
|
|
|
if not self.IsLibrary and CreateLibraryMakeFile:
|
|
for LibraryAutoGen in self.LibraryAutoGenList:
|
|
LibraryAutoGen.CreateMakeFile()
|
|
|
|
# CanSkip uses timestamps to determine build skipping
|
|
if self.CanSkip():
|
|
return
|
|
|
|
if len(self.CustomMakefile) == 0:
|
|
Makefile = GenMake.ModuleMakefile(self)
|
|
else:
|
|
Makefile = GenMake.CustomMakefile(self)
|
|
if Makefile.Generate():
|
|
EdkLogger.debug(EdkLogger.DEBUG_9, "Generated makefile for module %s [%s]" %
|
|
(self.Name, self.Arch))
|
|
else:
|
|
EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of makefile for module %s [%s]" %
|
|
(self.Name, self.Arch))
|
|
|
|
CreateTimeStamp()
|
|
|
|
MakefileType = Makefile._FileType
|
|
MakefileName = Makefile._FILE_NAME_[MakefileType]
|
|
MakefilePath = os.path.join(self.MakeFileDir, MakefileName)
|
|
|
|
MewIR = ModuleBuildCacheIR(self.MetaFile.Path, self.Arch)
|
|
MewIR.MakefilePath = MakefilePath
|
|
MewIR.DependencyHeaderFileSet = Makefile.DependencyHeaderFileSet
|
|
MewIR.CreateMakeFileDone = True
|
|
with GlobalData.cache_lock:
|
|
try:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.MakefilePath = MakefilePath
|
|
IR.DependencyHeaderFileSet = Makefile.DependencyHeaderFileSet
|
|
IR.CreateMakeFileDone = True
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
except:
|
|
gDict[(self.MetaFile.Path, self.Arch)] = MewIR
|
|
|
|
def CopyBinaryFiles(self):
|
|
for File in self.Module.Binaries:
|
|
SrcPath = File.Path
|
|
DstPath = os.path.join(self.OutputDir, os.path.basename(SrcPath))
|
|
CopyLongFilePath(SrcPath, DstPath)
|
|
## Create autogen code for the module and its dependent libraries
|
|
#
|
|
# @param CreateLibraryCodeFile Flag indicating if or not the code of
|
|
# dependent libraries will be created
|
|
#
|
|
def CreateCodeFile(self, CreateLibraryCodeFile=True):
|
|
gDict = GlobalData.gCacheIR
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].CreateCodeFileDone:
|
|
return
|
|
|
|
if self.IsCodeFileCreated:
|
|
return
|
|
|
|
# Need to generate PcdDatabase even PcdDriver is binarymodule
|
|
if self.IsBinaryModule and self.PcdIsDriver != '':
|
|
CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
|
|
return
|
|
if self.IsBinaryModule:
|
|
if self.IsLibrary:
|
|
self.CopyBinaryFiles()
|
|
return
|
|
|
|
if not self.IsLibrary and CreateLibraryCodeFile:
|
|
for LibraryAutoGen in self.LibraryAutoGenList:
|
|
LibraryAutoGen.CreateCodeFile()
|
|
|
|
# CanSkip uses timestamps to determine build skipping
|
|
if self.CanSkip():
|
|
return
|
|
self.LibraryAutoGenList
|
|
AutoGenList = []
|
|
IgoredAutoGenList = []
|
|
|
|
for File in self.AutoGenFileList:
|
|
if GenC.Generate(File.Path, self.AutoGenFileList[File], File.IsBinary):
|
|
AutoGenList.append(str(File))
|
|
else:
|
|
IgoredAutoGenList.append(str(File))
|
|
|
|
|
|
for ModuleType in self.DepexList:
|
|
# Ignore empty [depex] section or [depex] section for SUP_MODULE_USER_DEFINED module
|
|
if len(self.DepexList[ModuleType]) == 0 or ModuleType == SUP_MODULE_USER_DEFINED or ModuleType == SUP_MODULE_HOST_APPLICATION:
|
|
continue
|
|
|
|
Dpx = GenDepex.DependencyExpression(self.DepexList[ModuleType], ModuleType, True)
|
|
DpxFile = gAutoGenDepexFileName % {"module_name" : self.Name}
|
|
|
|
if len(Dpx.PostfixNotation) != 0:
|
|
self.DepexGenerated = True
|
|
|
|
if Dpx.Generate(path.join(self.OutputDir, DpxFile)):
|
|
AutoGenList.append(str(DpxFile))
|
|
else:
|
|
IgoredAutoGenList.append(str(DpxFile))
|
|
|
|
if IgoredAutoGenList == []:
|
|
EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] files for module %s [%s]" %
|
|
(" ".join(AutoGenList), self.Name, self.Arch))
|
|
elif AutoGenList == []:
|
|
EdkLogger.debug(EdkLogger.DEBUG_9, "Skipped the generation of [%s] files for module %s [%s]" %
|
|
(" ".join(IgoredAutoGenList), self.Name, self.Arch))
|
|
else:
|
|
EdkLogger.debug(EdkLogger.DEBUG_9, "Generated [%s] (skipped %s) files for module %s [%s]" %
|
|
(" ".join(AutoGenList), " ".join(IgoredAutoGenList), self.Name, self.Arch))
|
|
|
|
self.IsCodeFileCreated = True
|
|
MewIR = ModuleBuildCacheIR(self.MetaFile.Path, self.Arch)
|
|
MewIR.CreateCodeFileDone = True
|
|
with GlobalData.cache_lock:
|
|
try:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.CreateCodeFileDone = True
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
except:
|
|
gDict[(self.MetaFile.Path, self.Arch)] = MewIR
|
|
|
|
return AutoGenList
|
|
|
|
## Summarize the ModuleAutoGen objects of all libraries used by this module
|
|
@cached_property
|
|
def LibraryAutoGenList(self):
|
|
RetVal = []
|
|
for Library in self.DependentLibraryList:
|
|
La = ModuleAutoGen(
|
|
self.Workspace,
|
|
Library.MetaFile,
|
|
self.BuildTarget,
|
|
self.ToolChain,
|
|
self.Arch,
|
|
self.PlatformInfo.MetaFile,
|
|
self.DataPipe
|
|
)
|
|
La.IsLibrary = True
|
|
if La not in RetVal:
|
|
RetVal.append(La)
|
|
for Lib in La.CodaTargetList:
|
|
self._ApplyBuildRule(Lib.Target, TAB_UNKNOWN_FILE)
|
|
return RetVal
|
|
|
|
def GenModuleHash(self):
|
|
# Initialize a dictionary for each arch type
|
|
if self.Arch not in GlobalData.gModuleHash:
|
|
GlobalData.gModuleHash[self.Arch] = {}
|
|
|
|
# Early exit if module or library has been hashed and is in memory
|
|
if self.Name in GlobalData.gModuleHash[self.Arch]:
|
|
return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8')
|
|
|
|
# Initialze hash object
|
|
m = hashlib.md5()
|
|
|
|
# Add Platform level hash
|
|
m.update(GlobalData.gPlatformHash.encode('utf-8'))
|
|
|
|
# Add Package level hash
|
|
if self.DependentPackageList:
|
|
for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
|
|
if Pkg.PackageName in GlobalData.gPackageHash:
|
|
m.update(GlobalData.gPackageHash[Pkg.PackageName].encode('utf-8'))
|
|
|
|
# Add Library hash
|
|
if self.LibraryAutoGenList:
|
|
for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
|
|
if Lib.Name not in GlobalData.gModuleHash[self.Arch]:
|
|
Lib.GenModuleHash()
|
|
m.update(GlobalData.gModuleHash[self.Arch][Lib.Name].encode('utf-8'))
|
|
|
|
# Add Module self
|
|
with open(str(self.MetaFile), 'rb') as f:
|
|
Content = f.read()
|
|
m.update(Content)
|
|
|
|
# Add Module's source files
|
|
if self.SourceFileList:
|
|
for File in sorted(self.SourceFileList, key=lambda x: str(x)):
|
|
f = open(str(File), 'rb')
|
|
Content = f.read()
|
|
f.close()
|
|
m.update(Content)
|
|
|
|
GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
|
|
|
|
return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8')
|
|
|
|
def GenModuleFilesHash(self, gDict):
|
|
# Early exit if module or library has been hashed and is in memory
|
|
if (self.MetaFile.Path, self.Arch) in gDict:
|
|
if gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain:
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
# skip if the module cache already crashed
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].CacheCrash:
|
|
return
|
|
|
|
DependencyFileSet = set()
|
|
# Add Module Meta file
|
|
DependencyFileSet.add(self.MetaFile)
|
|
|
|
# Add Module's source files
|
|
if self.SourceFileList:
|
|
for File in set(self.SourceFileList):
|
|
DependencyFileSet.add(File)
|
|
|
|
# Add modules's include header files
|
|
# Search dependency file list for each source file
|
|
SourceFileList = []
|
|
OutPutFileList = []
|
|
for Target in self.IntroTargetList:
|
|
SourceFileList.extend(Target.Inputs)
|
|
OutPutFileList.extend(Target.Outputs)
|
|
if OutPutFileList:
|
|
for Item in OutPutFileList:
|
|
if Item in SourceFileList:
|
|
SourceFileList.remove(Item)
|
|
SearchList = []
|
|
for file_path in self.IncludePathList + self.BuildOptionIncPathList:
|
|
# skip the folders in platform BuildDir which are not been generated yet
|
|
if file_path.startswith(os.path.abspath(self.PlatformInfo.BuildDir)+os.sep):
|
|
continue
|
|
SearchList.append(file_path)
|
|
FileDependencyDict = {}
|
|
ForceIncludedFile = []
|
|
for F in SourceFileList:
|
|
# skip the files which are not been generated yet, because
|
|
# the SourceFileList usually contains intermediate build files, e.g. AutoGen.c
|
|
if not os.path.exists(F.Path):
|
|
continue
|
|
FileDependencyDict[F] = GenMake.GetDependencyList(self, self.FileDependCache, F, ForceIncludedFile, SearchList)
|
|
|
|
if FileDependencyDict:
|
|
for Dependency in FileDependencyDict.values():
|
|
DependencyFileSet.update(set(Dependency))
|
|
|
|
# Caculate all above dependency files hash
|
|
# Initialze hash object
|
|
FileList = []
|
|
m = hashlib.md5()
|
|
for File in sorted(DependencyFileSet, key=lambda x: str(x)):
|
|
if not os.path.exists(str(File)):
|
|
EdkLogger.quiet("[cache warning]: header file %s is missing for module: %s[%s]" % (File, self.MetaFile.Path, self.Arch))
|
|
continue
|
|
with open(str(File), 'rb') as f:
|
|
Content = f.read()
|
|
m.update(Content)
|
|
FileList.append((str(File), hashlib.md5(Content).hexdigest()))
|
|
|
|
|
|
MewIR = ModuleBuildCacheIR(self.MetaFile.Path, self.Arch)
|
|
MewIR.ModuleFilesHashDigest = m.digest()
|
|
MewIR.ModuleFilesHashHexDigest = m.hexdigest()
|
|
MewIR.ModuleFilesChain = FileList
|
|
with GlobalData.cache_lock:
|
|
try:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.ModuleFilesHashDigest = m.digest()
|
|
IR.ModuleFilesHashHexDigest = m.hexdigest()
|
|
IR.ModuleFilesChain = FileList
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
except:
|
|
gDict[(self.MetaFile.Path, self.Arch)] = MewIR
|
|
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
def GenPreMakefileHash(self, gDict):
|
|
# Early exit if module or library has been hashed and is in memory
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest:
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
# skip if the module cache already crashed
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].CacheCrash:
|
|
return
|
|
|
|
# skip binary module
|
|
if self.IsBinaryModule:
|
|
return
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest:
|
|
self.GenModuleFilesHash(gDict)
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest:
|
|
EdkLogger.quiet("[cache warning]: Cannot generate ModuleFilesHashDigest for module %s[%s]" %(self.MetaFile.Path, self.Arch))
|
|
return
|
|
|
|
# Initialze hash object
|
|
m = hashlib.md5()
|
|
|
|
# Add Platform level hash
|
|
if ('PlatformHash') in gDict:
|
|
m.update(gDict[('PlatformHash')].encode('utf-8'))
|
|
else:
|
|
EdkLogger.quiet("[cache warning]: PlatformHash is missing")
|
|
|
|
# Add Package level hash
|
|
if self.DependentPackageList:
|
|
for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
|
|
if (Pkg.PackageName, 'PackageHash') in gDict:
|
|
m.update(gDict[(Pkg.PackageName, 'PackageHash')].encode('utf-8'))
|
|
else:
|
|
EdkLogger.quiet("[cache warning]: %s PackageHash needed by %s[%s] is missing" %(Pkg.PackageName, self.MetaFile.Name, self.Arch))
|
|
|
|
# Add Library hash
|
|
if self.LibraryAutoGenList:
|
|
for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
|
|
if not (Lib.MetaFile.Path, Lib.Arch) in gDict or \
|
|
not gDict[(Lib.MetaFile.Path, Lib.Arch)].ModuleFilesHashDigest:
|
|
Lib.GenPreMakefileHash(gDict)
|
|
m.update(gDict[(Lib.MetaFile.Path, Lib.Arch)].ModuleFilesHashDigest)
|
|
|
|
# Add Module self
|
|
m.update(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest)
|
|
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.PreMakefileHashHexDigest = m.hexdigest()
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
def GenMakeHeaderFilesHash(self, gDict):
|
|
# Early exit if module or library has been hashed and is in memory
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest:
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
# skip if the module cache already crashed
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].CacheCrash:
|
|
return
|
|
|
|
# skip binary module
|
|
if self.IsBinaryModule:
|
|
return
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].CreateCodeFileDone:
|
|
if self.IsLibrary:
|
|
if (self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path) in GlobalData.libConstPcd:
|
|
self.ConstPcd = GlobalData.libConstPcd[(self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path)]
|
|
if (self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path) in GlobalData.Refes:
|
|
self.ReferenceModules = GlobalData.Refes[(self.MetaFile.File,self.MetaFile.Root,self.Arch,self.MetaFile.Path)]
|
|
self.CreateCodeFile()
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].CreateMakeFileDone:
|
|
self.CreateMakeFile(GenFfsList=GlobalData.FfsCmd.get((self.MetaFile.Path, self.Arch),[]))
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].CreateCodeFileDone or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].CreateMakeFileDone:
|
|
EdkLogger.quiet("[cache warning]: Cannot create CodeFile or Makefile for module %s[%s]" %(self.MetaFile.Path, self.Arch))
|
|
return
|
|
|
|
DependencyFileSet = set()
|
|
# Add Makefile
|
|
if gDict[(self.MetaFile.Path, self.Arch)].MakefilePath:
|
|
DependencyFileSet.add(gDict[(self.MetaFile.Path, self.Arch)].MakefilePath)
|
|
else:
|
|
EdkLogger.quiet("[cache warning]: makefile is missing for module %s[%s]" %(self.MetaFile.Path, self.Arch))
|
|
|
|
# Add header files
|
|
if gDict[(self.MetaFile.Path, self.Arch)].DependencyHeaderFileSet:
|
|
for File in gDict[(self.MetaFile.Path, self.Arch)].DependencyHeaderFileSet:
|
|
DependencyFileSet.add(File)
|
|
else:
|
|
EdkLogger.quiet("[cache warning]: No dependency header found for module %s[%s]" %(self.MetaFile.Path, self.Arch))
|
|
|
|
# Add AutoGen files
|
|
if self.AutoGenFileList:
|
|
for File in set(self.AutoGenFileList):
|
|
DependencyFileSet.add(File)
|
|
|
|
# Caculate all above dependency files hash
|
|
# Initialze hash object
|
|
FileList = []
|
|
m = hashlib.md5()
|
|
for File in sorted(DependencyFileSet, key=lambda x: str(x)):
|
|
if not os.path.exists(str(File)):
|
|
EdkLogger.quiet("[cache warning]: header file: %s doesn't exist for module: %s[%s]" % (File, self.MetaFile.Path, self.Arch))
|
|
continue
|
|
f = open(str(File), 'rb')
|
|
Content = f.read()
|
|
f.close()
|
|
m.update(Content)
|
|
FileList.append((str(File), hashlib.md5(Content).hexdigest()))
|
|
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.AutoGenFileList = self.AutoGenFileList.keys()
|
|
IR.MakeHeaderFilesHashChain = FileList
|
|
IR.MakeHeaderFilesHashDigest = m.digest()
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
def GenMakeHash(self, gDict):
|
|
# Early exit if module or library has been hashed and is in memory
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain:
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
# skip if the module cache already crashed
|
|
if (self.MetaFile.Path, self.Arch) in gDict and \
|
|
gDict[(self.MetaFile.Path, self.Arch)].CacheCrash:
|
|
return
|
|
|
|
# skip binary module
|
|
if self.IsBinaryModule:
|
|
return
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest:
|
|
self.GenModuleFilesHash(gDict)
|
|
if not gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest:
|
|
self.GenMakeHeaderFilesHash(gDict)
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashChain:
|
|
EdkLogger.quiet("[cache warning]: Cannot generate ModuleFilesHash or MakeHeaderFilesHash for module %s[%s]" %(self.MetaFile.Path, self.Arch))
|
|
return
|
|
|
|
# Initialze hash object
|
|
m = hashlib.md5()
|
|
MakeHashChain = []
|
|
|
|
# Add hash of makefile and dependency header files
|
|
m.update(gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashDigest)
|
|
New = list(set(gDict[(self.MetaFile.Path, self.Arch)].MakeHeaderFilesHashChain) - set(MakeHashChain))
|
|
New.sort(key=lambda x: str(x))
|
|
MakeHashChain += New
|
|
|
|
# Add Library hash
|
|
if self.LibraryAutoGenList:
|
|
for Lib in sorted(self.LibraryAutoGenList, key=lambda x: x.Name):
|
|
if not (Lib.MetaFile.Path, Lib.Arch) in gDict or \
|
|
not gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashChain:
|
|
Lib.GenMakeHash(gDict)
|
|
if not gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashDigest:
|
|
print("Cannot generate MakeHash for lib module:", Lib.MetaFile.Path, Lib.Arch)
|
|
continue
|
|
m.update(gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashDigest)
|
|
New = list(set(gDict[(Lib.MetaFile.Path, Lib.Arch)].MakeHashChain) - set(MakeHashChain))
|
|
New.sort(key=lambda x: str(x))
|
|
MakeHashChain += New
|
|
|
|
# Add Module self
|
|
m.update(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesHashDigest)
|
|
New = list(set(gDict[(self.MetaFile.Path, self.Arch)].ModuleFilesChain) - set(MakeHashChain))
|
|
New.sort(key=lambda x: str(x))
|
|
MakeHashChain += New
|
|
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.MakeHashDigest = m.digest()
|
|
IR.MakeHashHexDigest = m.hexdigest()
|
|
IR.MakeHashChain = MakeHashChain
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
|
|
return gDict[(self.MetaFile.Path, self.Arch)]
|
|
|
|
## Decide whether we can skip the left autogen and make process
|
|
def CanSkipbyPreMakefileCache(self, gDict):
|
|
if not GlobalData.gBinCacheSource:
|
|
return False
|
|
|
|
if gDict[(self.MetaFile.Path, self.Arch)].PreMakeCacheHit:
|
|
return True
|
|
|
|
if gDict[(self.MetaFile.Path, self.Arch)].CacheCrash:
|
|
return False
|
|
|
|
# If Module is binary, do not skip by cache
|
|
if self.IsBinaryModule:
|
|
return False
|
|
|
|
# .inc is contains binary information so do not skip by hash as well
|
|
for f_ext in self.SourceFileList:
|
|
if '.inc' in str(f_ext):
|
|
return False
|
|
|
|
# Get the module hash values from stored cache and currrent build
|
|
# then check whether cache hit based on the hash values
|
|
# if cache hit, restore all the files from cache
|
|
FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)
|
|
FfsDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name)
|
|
|
|
ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)]
|
|
ModuleHashPair = path.join(FileDir, self.Name + ".ModuleHashPair")
|
|
if not os.path.exists(ModuleHashPair):
|
|
EdkLogger.quiet("[cache warning]: Cannot find ModuleHashPair file: %s" % ModuleHashPair)
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.CacheCrash = True
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
return False
|
|
|
|
try:
|
|
with open(ModuleHashPair, 'r') as f:
|
|
ModuleHashPairList = json.load(f)
|
|
except:
|
|
EdkLogger.quiet("[cache warning]: fail to load ModuleHashPair file: %s" % ModuleHashPair)
|
|
return False
|
|
|
|
self.GenPreMakefileHash(gDict)
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest:
|
|
EdkLogger.quiet("[cache warning]: PreMakefileHashHexDigest is missing for module %s[%s]" %(self.MetaFile.Path, self.Arch))
|
|
return False
|
|
|
|
MakeHashStr = None
|
|
CurrentPreMakeHash = gDict[(self.MetaFile.Path, self.Arch)].PreMakefileHashHexDigest
|
|
for idx, (PreMakefileHash, MakeHash) in enumerate (ModuleHashPairList):
|
|
if PreMakefileHash == CurrentPreMakeHash:
|
|
MakeHashStr = str(MakeHash)
|
|
|
|
if not MakeHashStr:
|
|
return False
|
|
|
|
TargetHashDir = path.join(FileDir, MakeHashStr)
|
|
TargetFfsHashDir = path.join(FfsDir, MakeHashStr)
|
|
|
|
if not os.path.exists(TargetHashDir):
|
|
EdkLogger.quiet("[cache warning]: Cache folder is missing: %s" % TargetHashDir)
|
|
return False
|
|
|
|
for root, dir, files in os.walk(TargetHashDir):
|
|
for f in files:
|
|
File = path.join(root, f)
|
|
self.CacheCopyFile(self.OutputDir, TargetHashDir, File)
|
|
if os.path.exists(TargetFfsHashDir):
|
|
for root, dir, files in os.walk(TargetFfsHashDir):
|
|
for f in files:
|
|
File = path.join(root, f)
|
|
self.CacheCopyFile(self.FfsOutputDir, TargetFfsHashDir, File)
|
|
|
|
if self.Name == "PcdPeim" or self.Name == "PcdDxe":
|
|
CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
|
|
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.PreMakeCacheHit = True
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
print("[cache hit]: checkpoint_PreMakefile:", self.MetaFile.Path, self.Arch)
|
|
#EdkLogger.quiet("cache hit: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return True
|
|
|
|
## Decide whether we can skip the make process
|
|
def CanSkipbyMakeCache(self, gDict):
|
|
if not GlobalData.gBinCacheSource:
|
|
return False
|
|
|
|
if gDict[(self.MetaFile.Path, self.Arch)].MakeCacheHit:
|
|
return True
|
|
|
|
if gDict[(self.MetaFile.Path, self.Arch)].CacheCrash:
|
|
return False
|
|
|
|
# If Module is binary, do not skip by cache
|
|
if self.IsBinaryModule:
|
|
print("[cache miss]: checkpoint_Makefile: binary module:", self.MetaFile.Path, self.Arch)
|
|
return False
|
|
|
|
# .inc is contains binary information so do not skip by hash as well
|
|
for f_ext in self.SourceFileList:
|
|
if '.inc' in str(f_ext):
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.MakeCacheHit = False
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
print("[cache miss]: checkpoint_Makefile: .inc module:", self.MetaFile.Path, self.Arch)
|
|
return False
|
|
|
|
# Get the module hash values from stored cache and currrent build
|
|
# then check whether cache hit based on the hash values
|
|
# if cache hit, restore all the files from cache
|
|
FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)
|
|
FfsDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, TAB_FV_DIRECTORY, "Ffs", self.Guid + self.Name)
|
|
|
|
ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)]
|
|
ModuleHashPair = path.join(FileDir, self.Name + ".ModuleHashPair")
|
|
if not os.path.exists(ModuleHashPair):
|
|
EdkLogger.quiet("[cache warning]: Cannot find ModuleHashPair file: %s" % ModuleHashPair)
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.CacheCrash = True
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
return False
|
|
|
|
try:
|
|
with open(ModuleHashPair, 'r') as f:
|
|
ModuleHashPairList = json.load(f)
|
|
except:
|
|
EdkLogger.quiet("[cache warning]: fail to load ModuleHashPair file: %s" % ModuleHashPair)
|
|
return False
|
|
|
|
self.GenMakeHash(gDict)
|
|
if not (self.MetaFile.Path, self.Arch) in gDict or \
|
|
not gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest:
|
|
EdkLogger.quiet("[cache warning]: MakeHashHexDigest is missing for module %s[%s]" %(self.MetaFile.Path, self.Arch))
|
|
return False
|
|
|
|
MakeHashStr = None
|
|
CurrentMakeHash = gDict[(self.MetaFile.Path, self.Arch)].MakeHashHexDigest
|
|
for idx, (PreMakefileHash, MakeHash) in enumerate (ModuleHashPairList):
|
|
if MakeHash == CurrentMakeHash:
|
|
MakeHashStr = str(MakeHash)
|
|
|
|
if not MakeHashStr:
|
|
print("[cache miss]: checkpoint_Makefile:", self.MetaFile.Path, self.Arch)
|
|
return False
|
|
|
|
TargetHashDir = path.join(FileDir, MakeHashStr)
|
|
TargetFfsHashDir = path.join(FfsDir, MakeHashStr)
|
|
if not os.path.exists(TargetHashDir):
|
|
EdkLogger.quiet("[cache warning]: Cache folder is missing: %s" % TargetHashDir)
|
|
return False
|
|
|
|
for root, dir, files in os.walk(TargetHashDir):
|
|
for f in files:
|
|
File = path.join(root, f)
|
|
self.CacheCopyFile(self.OutputDir, TargetHashDir, File)
|
|
|
|
if os.path.exists(TargetFfsHashDir):
|
|
for root, dir, files in os.walk(TargetFfsHashDir):
|
|
for f in files:
|
|
File = path.join(root, f)
|
|
self.CacheCopyFile(self.FfsOutputDir, TargetFfsHashDir, File)
|
|
|
|
if self.Name == "PcdPeim" or self.Name == "PcdDxe":
|
|
CreatePcdDatabaseCode(self, TemplateString(), TemplateString())
|
|
with GlobalData.cache_lock:
|
|
IR = gDict[(self.MetaFile.Path, self.Arch)]
|
|
IR.MakeCacheHit = True
|
|
gDict[(self.MetaFile.Path, self.Arch)] = IR
|
|
print("[cache hit]: checkpoint_Makefile:", self.MetaFile.Path, self.Arch)
|
|
return True
|
|
|
|
## Show the first file name which causes cache miss
|
|
def PrintFirstMakeCacheMissFile(self, gDict):
|
|
if not GlobalData.gBinCacheSource:
|
|
return
|
|
|
|
# skip if the module cache already crashed
|
|
if gDict[(self.MetaFile.Path, self.Arch)].CacheCrash:
|
|
return
|
|
|
|
# skip binary module
|
|
if self.IsBinaryModule:
|
|
return
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict:
|
|
return
|
|
|
|
# Only print cache miss file for the MakeCache not hit module
|
|
if gDict[(self.MetaFile.Path, self.Arch)].MakeCacheHit:
|
|
return
|
|
|
|
if not gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain:
|
|
EdkLogger.quiet("[cache insight]: MakeHashChain is missing for: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return
|
|
|
|
# Find the cache dir name through the .ModuleHashPair file info
|
|
FileDir = path.join(GlobalData.gBinCacheSource, self.PlatformInfo.OutputDir, self.BuildTarget + "_" + self.ToolChain, self.Arch, self.SourceDir, self.MetaFile.BaseName)
|
|
|
|
ModuleHashPairList = [] # tuple list: [tuple(PreMakefileHash, MakeHash)]
|
|
ModuleHashPair = path.join(FileDir, self.Name + ".ModuleHashPair")
|
|
if not os.path.exists(ModuleHashPair):
|
|
EdkLogger.quiet("[cache insight]: Cannot find ModuleHashPair file for module: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return
|
|
|
|
try:
|
|
with open(ModuleHashPair, 'r') as f:
|
|
ModuleHashPairList = json.load(f)
|
|
except:
|
|
EdkLogger.quiet("[cache insight]: Cannot load ModuleHashPair file for module: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return
|
|
|
|
MakeHashSet = set()
|
|
for idx, (PreMakefileHash, MakeHash) in enumerate (ModuleHashPairList):
|
|
TargetHashDir = path.join(FileDir, str(MakeHash))
|
|
if os.path.exists(TargetHashDir):
|
|
MakeHashSet.add(MakeHash)
|
|
if not MakeHashSet:
|
|
EdkLogger.quiet("[cache insight]: Cannot find valid cache dir for module: %s[%s]" % (self.MetaFile.Path, self.Arch))
|
|
return
|
|
|
|
TargetHash = list(MakeHashSet)[0]
|
|
TargetHashDir = path.join(FileDir, str(TargetHash))
|
|
if len(MakeHashSet) > 1 :
|
|
EdkLogger.quiet("[cache insight]: found multiple cache dirs for this module, random select dir '%s' to search the first cache miss file: %s[%s]" % (TargetHash, self.MetaFile.Path, self.Arch))
|
|
|
|
ListFile = path.join(TargetHashDir, self.Name + '.MakeHashChain')
|
|
if os.path.exists(ListFile):
|
|
try:
|
|
f = open(ListFile, 'r')
|
|
CachedList = json.load(f)
|
|
f.close()
|
|
except:
|
|
EdkLogger.quiet("[cache insight]: Cannot load MakeHashChain file: %s" % ListFile)
|
|
return
|
|
else:
|
|
EdkLogger.quiet("[cache insight]: Cannot find MakeHashChain file: %s" % ListFile)
|
|
return
|
|
|
|
CurrentList = gDict[(self.MetaFile.Path, self.Arch)].MakeHashChain
|
|
for idx, (file, hash) in enumerate (CurrentList):
|
|
(filecached, hashcached) = CachedList[idx]
|
|
if file != filecached:
|
|
EdkLogger.quiet("[cache insight]: first different file in %s[%s] is %s, the cached one is %s" % (self.MetaFile.Path, self.Arch, file, filecached))
|
|
break
|
|
if hash != hashcached:
|
|
EdkLogger.quiet("[cache insight]: first cache miss file in %s[%s] is %s" % (self.MetaFile.Path, self.Arch, file))
|
|
break
|
|
|
|
return True
|
|
|
|
## Decide whether we can skip the ModuleAutoGen process
|
|
def CanSkipbyCache(self, gDict):
|
|
# Hashing feature is off
|
|
if not GlobalData.gBinCacheSource:
|
|
return False
|
|
|
|
if self in GlobalData.gBuildHashSkipTracking:
|
|
return GlobalData.gBuildHashSkipTracking[self]
|
|
|
|
# If library or Module is binary do not skip by hash
|
|
if self.IsBinaryModule:
|
|
GlobalData.gBuildHashSkipTracking[self] = False
|
|
return False
|
|
|
|
# .inc is contains binary information so do not skip by hash as well
|
|
for f_ext in self.SourceFileList:
|
|
if '.inc' in str(f_ext):
|
|
GlobalData.gBuildHashSkipTracking[self] = False
|
|
return False
|
|
|
|
if not (self.MetaFile.Path, self.Arch) in gDict:
|
|
return False
|
|
|
|
if gDict[(self.MetaFile.Path, self.Arch)].PreMakeCacheHit:
|
|
GlobalData.gBuildHashSkipTracking[self] = True
|
|
return True
|
|
|
|
if gDict[(self.MetaFile.Path, self.Arch)].MakeCacheHit:
|
|
GlobalData.gBuildHashSkipTracking[self] = True
|
|
return True
|
|
|
|
return False
|
|
|
|
## Decide whether we can skip the ModuleAutoGen process
|
|
# If any source file is newer than the module than we cannot skip
|
|
#
|
|
def CanSkip(self):
|
|
# Don't skip if cache feature enabled
|
|
if GlobalData.gUseHashCache or GlobalData.gBinCacheDest or GlobalData.gBinCacheSource:
|
|
return False
|
|
if self.MakeFileDir in GlobalData.gSikpAutoGenCache:
|
|
return True
|
|
if not os.path.exists(self.TimeStampPath):
|
|
return False
|
|
#last creation time of the module
|
|
DstTimeStamp = os.stat(self.TimeStampPath)[8]
|
|
|
|
SrcTimeStamp = self.Workspace._SrcTimeStamp
|
|
if SrcTimeStamp > DstTimeStamp:
|
|
return False
|
|
|
|
with open(self.TimeStampPath,'r') as f:
|
|
for source in f:
|
|
source = source.rstrip('\n')
|
|
if not os.path.exists(source):
|
|
return False
|
|
if source not in ModuleAutoGen.TimeDict :
|
|
ModuleAutoGen.TimeDict[source] = os.stat(source)[8]
|
|
if ModuleAutoGen.TimeDict[source] > DstTimeStamp:
|
|
return False
|
|
GlobalData.gSikpAutoGenCache.add(self.MakeFileDir)
|
|
return True
|
|
|
|
@cached_property
|
|
def TimeStampPath(self):
|
|
return os.path.join(self.MakeFileDir, 'AutoGenTimeStamp')
|