mirror of https://github.com/acidanthera/audk.git
BaseTools: Library hashing fix and optimization for --hash feature
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=1788 In V3: Must generate hashes before attempting to copy from cache for hash verifcation In V2: Build failure caused by passing incorrect boolean parameter to SaveFileOnChange(). Fixed for patch instances. Library hashing is now supported by the --hash feature. The --hash feature implementation assumed that the hashing could be done in place once per module, but that isn't true for libraries due to the fact that they are built as dependencies. So on a clean build, we now generate the .hash after the library dependencies are complete. Added early escape as optimization, if hash already exists in memory. Signed-off-by: Christian Rodriguez <christian.rodriguez@intel.com> Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <liming.gao@intel.com> Cc: Yonghong Zhu <yonghong.zhu@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
This commit is contained in:
parent
66b845ae06
commit
a7ef158b07
|
@ -3935,6 +3935,7 @@ class ModuleAutoGen(AutoGen):
|
||||||
f = open(HashFile, 'r')
|
f = open(HashFile, 'r')
|
||||||
CacheHash = f.read()
|
CacheHash = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
|
self.GenModuleHash()
|
||||||
if GlobalData.gModuleHash[self.Arch][self.Name]:
|
if GlobalData.gModuleHash[self.Arch][self.Name]:
|
||||||
if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:
|
if CacheHash == GlobalData.gModuleHash[self.Arch][self.Name]:
|
||||||
for root, dir, files in os.walk(FileDir):
|
for root, dir, files in os.walk(FileDir):
|
||||||
|
@ -4093,13 +4094,20 @@ class ModuleAutoGen(AutoGen):
|
||||||
return RetVal
|
return RetVal
|
||||||
|
|
||||||
def GenModuleHash(self):
|
def GenModuleHash(self):
|
||||||
|
# Initialize a dictionary for each arch type
|
||||||
if self.Arch not in GlobalData.gModuleHash:
|
if self.Arch not in GlobalData.gModuleHash:
|
||||||
GlobalData.gModuleHash[self.Arch] = {}
|
GlobalData.gModuleHash[self.Arch] = {}
|
||||||
if self.Name in GlobalData.gModuleHash[self.Arch] and GlobalData.gBinCacheSource and self.AttemptModuleCacheCopy():
|
|
||||||
return False
|
# 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()
|
m = hashlib.md5()
|
||||||
|
|
||||||
# Add Platform level hash
|
# Add Platform level hash
|
||||||
m.update(GlobalData.gPlatformHash.encode('utf-8'))
|
m.update(GlobalData.gPlatformHash.encode('utf-8'))
|
||||||
|
|
||||||
# Add Package level hash
|
# Add Package level hash
|
||||||
if self.DependentPackageList:
|
if self.DependentPackageList:
|
||||||
for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
|
for Pkg in sorted(self.DependentPackageList, key=lambda x: x.PackageName):
|
||||||
|
@ -4118,6 +4126,7 @@ class ModuleAutoGen(AutoGen):
|
||||||
Content = f.read()
|
Content = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
m.update(Content)
|
m.update(Content)
|
||||||
|
|
||||||
# Add Module's source files
|
# Add Module's source files
|
||||||
if self.SourceFileList:
|
if self.SourceFileList:
|
||||||
for File in sorted(self.SourceFileList, key=lambda x: str(x)):
|
for File in sorted(self.SourceFileList, key=lambda x: str(x)):
|
||||||
|
@ -4126,27 +4135,45 @@ class ModuleAutoGen(AutoGen):
|
||||||
f.close()
|
f.close()
|
||||||
m.update(Content)
|
m.update(Content)
|
||||||
|
|
||||||
ModuleHashFile = path.join(self.BuildDir, self.Name + ".hash")
|
GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
|
||||||
if self.Name not in GlobalData.gModuleHash[self.Arch]:
|
|
||||||
GlobalData.gModuleHash[self.Arch][self.Name] = m.hexdigest()
|
return GlobalData.gModuleHash[self.Arch][self.Name].encode('utf-8')
|
||||||
if GlobalData.gBinCacheSource and self.AttemptModuleCacheCopy():
|
|
||||||
return False
|
|
||||||
return SaveFileOnChange(ModuleHashFile, m.hexdigest(), False)
|
|
||||||
|
|
||||||
## Decide whether we can skip the ModuleAutoGen process
|
## Decide whether we can skip the ModuleAutoGen process
|
||||||
def CanSkipbyHash(self):
|
def CanSkipbyHash(self):
|
||||||
|
# Hashing feature is off
|
||||||
|
if not GlobalData.gUseHashCache:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Initialize a dictionary for each arch type
|
||||||
|
if self.Arch not in GlobalData.gBuildHashSkipTracking:
|
||||||
|
GlobalData.gBuildHashSkipTracking[self.Arch] = dict()
|
||||||
|
|
||||||
# If library or Module is binary do not skip by hash
|
# If library or Module is binary do not skip by hash
|
||||||
if self.IsBinaryModule:
|
if self.IsBinaryModule:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# .inc is contains binary information so do not skip by hash as well
|
# .inc is contains binary information so do not skip by hash as well
|
||||||
for f_ext in self.SourceFileList:
|
for f_ext in self.SourceFileList:
|
||||||
if '.inc' in str(f_ext):
|
if '.inc' in str(f_ext):
|
||||||
return False
|
return False
|
||||||
if GlobalData.gUseHashCache:
|
|
||||||
# If there is a valid hash or function generated a valid hash; function will return False
|
# Use Cache, if exists and if Module has a copy in cache
|
||||||
# and the statement below will return True
|
if GlobalData.gBinCacheSource and self.AttemptModuleCacheCopy():
|
||||||
return not self.GenModuleHash()
|
return True
|
||||||
return False
|
|
||||||
|
# Early exit for libraries that haven't yet finished building
|
||||||
|
HashFile = path.join(self.BuildDir, self.Name + ".hash")
|
||||||
|
if self.IsLibrary and not os.path.exists(HashFile):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Return a Boolean based on if can skip by hash, either from memory or from IO.
|
||||||
|
if self.Name not in GlobalData.gBuildHashSkipTracking[self.Arch]:
|
||||||
|
# If hashes are the same, SaveFileOnChange() will return False.
|
||||||
|
GlobalData.gBuildHashSkipTracking[self.Arch][self.Name] = not SaveFileOnChange(HashFile, self.GenModuleHash(), True)
|
||||||
|
return GlobalData.gBuildHashSkipTracking[self.Arch][self.Name]
|
||||||
|
else:
|
||||||
|
return GlobalData.gBuildHashSkipTracking[self.Arch][self.Name]
|
||||||
|
|
||||||
## Decide whether we can skip the ModuleAutoGen process
|
## Decide whether we can skip the ModuleAutoGen process
|
||||||
# If any source file is newer than the module than we cannot skip
|
# If any source file is newer than the module than we cannot skip
|
||||||
|
|
|
@ -112,3 +112,9 @@ gSikpAutoGenCache = set()
|
||||||
# Dictionary for tracking Module build status as success or failure
|
# Dictionary for tracking Module build status as success or failure
|
||||||
# False -> Fail : True -> Success
|
# False -> Fail : True -> Success
|
||||||
gModuleBuildTracking = dict()
|
gModuleBuildTracking = dict()
|
||||||
|
|
||||||
|
# Dictionary of booleans that dictate whether a module or
|
||||||
|
# library can be skiped
|
||||||
|
# Top Dict: Key: Arch Type Value: Dictionary
|
||||||
|
# Second Dict: Key: Module\Library Name Value: True\False
|
||||||
|
gBuildHashSkipTracking = dict()
|
||||||
|
|
|
@ -593,7 +593,7 @@ class BuildTask:
|
||||||
#
|
#
|
||||||
def AddDependency(self, Dependency):
|
def AddDependency(self, Dependency):
|
||||||
for Dep in Dependency:
|
for Dep in Dependency:
|
||||||
if not Dep.BuildObject.IsBinaryModule:
|
if not Dep.BuildObject.IsBinaryModule and not Dep.BuildObject.CanSkipbyHash():
|
||||||
self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list
|
self.DependencyList.append(BuildTask.New(Dep)) # BuildTask list
|
||||||
|
|
||||||
## The thread wrapper of LaunchCommand function
|
## The thread wrapper of LaunchCommand function
|
||||||
|
@ -605,6 +605,11 @@ class BuildTask:
|
||||||
try:
|
try:
|
||||||
self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir)
|
self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir)
|
||||||
self.CompleteFlag = True
|
self.CompleteFlag = True
|
||||||
|
|
||||||
|
# Run hash operation post dependency, to account for libs
|
||||||
|
if GlobalData.gUseHashCache and self.BuildItem.BuildObject.IsLibrary:
|
||||||
|
HashFile = path.join(self.BuildItem.BuildObject.BuildDir, self.BuildItem.BuildObject.Name + ".hash")
|
||||||
|
SaveFileOnChange(HashFile, self.BuildItem.BuildObject.GenModuleHash(), True)
|
||||||
except:
|
except:
|
||||||
#
|
#
|
||||||
# TRICK: hide the output of threads left running, so that the user can
|
# TRICK: hide the output of threads left running, so that the user can
|
||||||
|
|
Loading…
Reference in New Issue