BaseTools: Enhance Basetool for incremental build

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=2311

Include dependency file in Makefile to enhance
incremental build

Signed-off-by: Bob Feng <bob.c.feng@intel.com>

Cc: Liming Gao <liming.gao@intel.com>
Cc: Steven Shi <steven.shi@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
This commit is contained in:
Bob Feng 2019-11-20 10:58:30 +08:00 committed by mergify[bot]
parent cb277815d5
commit 0c3e8e9947
4 changed files with 380 additions and 73 deletions

View File

@ -185,6 +185,12 @@ class BuildFile(object):
self._FileType = FileType self._FileType = FileType
FileContent = self._TEMPLATE_.Replace(self._TemplateDict) FileContent = self._TEMPLATE_.Replace(self._TemplateDict)
FileName = self._FILE_NAME_[FileType] FileName = self._FILE_NAME_[FileType]
if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "deps.txt")):
with open(os.path.join(self._AutoGenObject.MakeFileDir, "deps.txt"),"w+") as fd:
fd.write("")
if not os.path.exists(os.path.join(self._AutoGenObject.MakeFileDir, "dependency")):
with open(os.path.join(self._AutoGenObject.MakeFileDir, "dependency"),"w+") as fd:
fd.write("")
return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False) return SaveFileOnChange(os.path.join(self._AutoGenObject.MakeFileDir, FileName), FileContent, False)
## Return a list of directory creation command string ## Return a list of directory creation command string
@ -304,9 +310,6 @@ MAKE_FILE = ${makefile_path}
${BEGIN}${file_macro} ${BEGIN}${file_macro}
${END} ${END}
COMMON_DEPS = ${BEGIN}${common_dependency_file} \\
${END}
# #
# Overridable Target Macro Definitions # Overridable Target Macro Definitions
# #
@ -382,6 +385,8 @@ gen_fds:
\t@"$(MAKE)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds \t@"$(MAKE)" $(MAKE_FLAGS) -f $(BUILD_DIR)${separator}${makefile_name} fds
\t@cd $(MODULE_BUILD_DIR) \t@cd $(MODULE_BUILD_DIR)
${INCLUDETAG}
# #
# Individual Object Build Targets # Individual Object Build Targets
# #
@ -515,9 +520,6 @@ cleanlib:
# Remove duplicated include path, if any # Remove duplicated include path, if any
if Attr == "FLAGS": if Attr == "FLAGS":
Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList) Value = RemoveDupOption(Value, IncPrefix, MyAgo.IncludePathList)
if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and Tool == 'CC' and '/GM' in Value:
Value = Value.replace(' /MP', '')
MyAgo.BuildOption[Tool][Attr] = Value
if Tool == "OPTROM" and PCI_COMPRESS_Flag: if Tool == "OPTROM" and PCI_COMPRESS_Flag:
ValueList = Value.split() ValueList = Value.split()
if ValueList: if ValueList:
@ -540,7 +542,7 @@ cleanlib:
UnexpandMacro = [] UnexpandMacro = []
NewStr = [] NewStr = []
for Str in StrList: for Str in StrList:
if '$' in Str: if '$' in Str or '-MMD' in Str or '-MF' in Str:
UnexpandMacro.append(Str) UnexpandMacro.append(Str)
else: else:
NewStr.append(Str) NewStr.append(Str)
@ -590,10 +592,9 @@ cleanlib:
) )
FileMacroList.append(FileMacro) FileMacroList.append(FileMacro)
# Add support when compiling .nasm source files # Add support when compiling .nasm source files
for File in self.FileCache.keys(): IncludePathList = []
if not str(File).endswith('.nasm'): asmsource = [item for item in MyAgo.SourceFileList if item.File.upper().endswith((".NASM",".ASM",".NASMB","S"))]
continue if asmsource:
IncludePathList = []
for P in MyAgo.IncludePathList: for P in MyAgo.IncludePathList:
IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros) IncludePath = self._INC_FLAG_['NASM'] + self.PlaceMacro(P, self.Macros)
if IncludePath.endswith(os.sep): if IncludePath.endswith(os.sep):
@ -606,7 +607,6 @@ cleanlib:
IncludePath = os.path.join(IncludePath, '') IncludePath = os.path.join(IncludePath, '')
IncludePathList.append(IncludePath) IncludePathList.append(IncludePath)
FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name": "NASM_INC", "source_file": IncludePathList})) FileMacroList.append(self._FILE_MACRO_TEMPLATE.Replace({"macro_name": "NASM_INC", "source_file": IncludePathList}))
break
# Generate macros used to represent files containing list of input files # Generate macros used to represent files containing list of input files
for ListFileMacro in self.ListFileMacros: for ListFileMacro in self.ListFileMacros:
@ -696,6 +696,7 @@ cleanlib:
"file_macro" : FileMacroList, "file_macro" : FileMacroList,
"file_build_target" : self.BuildTargetList, "file_build_target" : self.BuildTargetList,
"backward_compatible_target": BcTargetList, "backward_compatible_target": BcTargetList,
"INCLUDETAG" : self._INCLUDE_CMD_[self._FileType] + " " + os.path.join("$(MODULE_BUILD_DIR)","dependency")
} }
return MakefileTemplateDict return MakefileTemplateDict
@ -903,16 +904,10 @@ cleanlib:
if Item in SourceFileList: if Item in SourceFileList:
SourceFileList.remove(Item) SourceFileList.remove(Item)
FileDependencyDict = self.GetFileDependency( FileDependencyDict = {item:ForceIncludedFile for item in SourceFileList}
SourceFileList,
ForceIncludedFile,
self._AutoGenObject.IncludePathList + self._AutoGenObject.BuildOptionIncPathList
)
for Dependency in FileDependencyDict.values():
if FileDependencyDict: self.DependencyHeaderFileSet.update(set(Dependency))
for Dependency in FileDependencyDict.values():
self.DependencyHeaderFileSet.update(set(Dependency))
# Get a set of unique package includes from MetaFile # Get a set of unique package includes from MetaFile
parentMetaFileIncludes = set() parentMetaFileIncludes = set()
@ -972,42 +967,16 @@ cleanlib:
ExtraData = "Local Header: " + aFile + " not found in " + self._AutoGenObject.MetaFile.Path ExtraData = "Local Header: " + aFile + " not found in " + self._AutoGenObject.MetaFile.Path
) )
DepSet = None
for File,Dependency in FileDependencyDict.items(): for File,Dependency in FileDependencyDict.items():
if not Dependency: if not Dependency:
FileDependencyDict[File] = ['$(FORCE_REBUILD)']
continue continue
self._AutoGenObject.AutoGenDepSet |= set(Dependency) self._AutoGenObject.AutoGenDepSet |= set(Dependency)
# skip non-C files
if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
continue
elif DepSet is None:
DepSet = set(Dependency)
else:
DepSet &= set(Dependency)
# in case nothing in SourceFileList
if DepSet is None:
DepSet = set()
#
# Extract common files list in the dependency files
#
for File in DepSet:
self.CommonFileDependency.append(self.PlaceMacro(File.Path, self.Macros))
CmdSumDict = {} CmdSumDict = {}
CmdTargetDict = {} CmdTargetDict = {}
CmdCppDict = {} CmdCppDict = {}
DependencyDict = FileDependencyDict.copy() DependencyDict = FileDependencyDict.copy()
for File in FileDependencyDict:
# skip non-C files
if File.Ext not in [".c", ".C"] or File.Name == "AutoGen.c":
continue
NewDepSet = set(FileDependencyDict[File])
NewDepSet -= DepSet
FileDependencyDict[File] = ["$(COMMON_DEPS)"] + list(NewDepSet)
DependencyDict[File] = list(NewDepSet)
# Convert target description object to target string in makefile # Convert target description object to target string in makefile
if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets: if self._AutoGenObject.BuildRuleFamily == TAB_COMPILER_MSFT and TAB_C_CODE_FILE in self._AutoGenObject.Targets:
@ -1080,17 +1049,13 @@ cleanlib:
else: else:
CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path] CmdCppDict[item.Target.SubDir] = ['$(MAKE_FILE)', Path]
if CppPath.Path in DependencyDict: if CppPath.Path in DependencyDict:
if '$(FORCE_REBUILD)' in DependencyDict[CppPath.Path]: for Temp in DependencyDict[CppPath.Path]:
if '$(FORCE_REBUILD)' not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]): try:
CmdCppDict[item.Target.SubDir].append('$(FORCE_REBUILD)') Path = self.PlaceMacro(Temp.Path, self.Macros)
else: except:
for Temp in DependencyDict[CppPath.Path]: continue
try: if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
Path = self.PlaceMacro(Temp.Path, self.Macros) CmdCppDict[item.Target.SubDir].append(Path)
except:
continue
if Path not in (self.CommonFileDependency + CmdCppDict[item.Target.SubDir]):
CmdCppDict[item.Target.SubDir].append(Path)
if T.Commands: if T.Commands:
CommandList = T.Commands[:] CommandList = T.Commands[:]
for Item in CommandList[:]: for Item in CommandList[:]:
@ -1109,7 +1074,7 @@ cleanlib:
CommandList.pop(Index) CommandList.pop(Index)
if SingleCommandList[-1].endswith("%s%s.c" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])): if SingleCommandList[-1].endswith("%s%s.c" % (TAB_SLASH, CmdSumDict[CmdSign[3:].rsplit(TAB_SLASH, 1)[0]])):
Cpplist = CmdCppDict[T.Target.SubDir] Cpplist = CmdCppDict[T.Target.SubDir]
Cpplist.insert(0, '$(OBJLIST_%d): $(COMMON_DEPS)' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir)) Cpplist.insert(0, '$(OBJLIST_%d): ' % list(self.ObjTargetDict.keys()).index(T.Target.SubDir))
T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign]) T.Commands[Index] = '%s\n\t%s' % (' \\\n\t'.join(Cpplist), CmdTargetDict[CmdSign])
else: else:
T.Commands.pop(Index) T.Commands.pop(Index)

View File

@ -0,0 +1,284 @@
## @file
# Build cache intermediate result and state
#
# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
from Common.caching import cached_property
import Common.EdkLogger as EdkLogger
import Common.LongFilePathOs as os
from Common.BuildToolError import *
from Common.Misc import SaveFileOnChange, PathClass
from Common.Misc import TemplateString
import sys
gIsFileMap = {}
if sys.platform == "win32":
_INCLUDE_DEPS_TEMPLATE = TemplateString('''
${BEGIN}
!IF EXIST(${deps_file})
!INCLUDE ${deps_file}
!ENDIF
${END}
''')
else:
_INCLUDE_DEPS_TEMPLATE = TemplateString('''
${BEGIN}
-include ${deps_file}
${END}
''')
DEP_FILE_TAIL = "# Updated \n"
class IncludesAutoGen():
""" This class is to manage the dependent files witch are used in Makefile to support incremental build.
1. C files:
1. MSVS.
cl.exe has a build option /showIncludes to display include files on stdout. Build tool captures
that messages and generate dependency files, .deps files.
2. CLANG and GCC
-MMD -MF build option are used to generate dependency files by compiler. Build tool updates the
.deps files.
2. ASL files:
1. Trim find out all the included files with asl specific include format and generate .trim.deps file.
2. ASL PP use c preprocessor to find out all included files with #include format and generate a .deps file
3. build tool updates the .deps file
3. ASM files (.asm, .s or .nasm):
1. Trim find out all the included files with asl specific include format and generate .trim.deps file.
2. ASM PP use c preprocessor to find out all included files with #include format and generate a deps file
3. build tool updates the .deps file
"""
def __init__(self, makefile_folder, ModuleAuto):
self.d_folder = makefile_folder
self.makefile_folder = makefile_folder
self.module_autogen = ModuleAuto
self.ToolChainFamily = ModuleAuto.ToolChainFamily
self.workspace = ModuleAuto.WorkspaceDir
def CreateModuleDeps(self):
SaveFileOnChange(os.path.join(self.makefile_folder,"deps.txt"),"\n".join(self.DepsCollection),False)
def CreateDepsInclude(self):
deps_file = {'deps_file':self.deps_files}
try:
deps_include_str = _INCLUDE_DEPS_TEMPLATE.Replace(deps_file)
except Exception as e:
print(e)
SaveFileOnChange(os.path.join(self.makefile_folder,"dependency"),deps_include_str,False)
@cached_property
def deps_files(self):
""" Get all .deps file under module build folder. """
deps_files = []
for root, _, files in os.walk(self.d_folder, topdown=False):
for name in files:
if not name.endswith(".deps"):
continue
abspath = os.path.join(root, name)
deps_files.append(abspath)
return deps_files
@cached_property
def DepsCollection(self):
""" Collect all the dependency files list from all .deps files under a module's build folder """
includes = set()
targetname = [item[0].Name for item in self.TargetFileList.values()]
for abspath in self.deps_files:
try:
with open(abspath,"r") as fd:
lines = fd.readlines()
firstlineitems = lines[0].split(": ")
dependency_file = firstlineitems[1].strip(" \\\n")
dependency_file = dependency_file.strip('''"''')
if dependency_file:
if os.path.normpath(dependency_file +".deps") == abspath:
continue
filename = os.path.basename(dependency_file).strip()
if filename not in self.SourceFileList and filename not in targetname:
includes.add(dependency_file.strip())
for item in lines[1:]:
if item == DEP_FILE_TAIL:
continue
dependency_file = item.strip(" \\\n")
dependency_file = dependency_file.strip('''"''')
if os.path.normpath(dependency_file +".deps") == abspath:
continue
filename = os.path.basename(dependency_file).strip()
if filename in self.SourceFileList:
continue
if filename in targetname:
continue
includes.add(dependency_file.strip())
except Exception as e:
EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False)
continue
rt = sorted(list(set([item.strip(' " \\\n') for item in includes])))
return rt
@cached_property
def SourceFileList(self):
""" Get a map of module's source files name to module's source files path """
source = {os.path.basename(item.File):item.Path for item in self.module_autogen.SourceFileList}
middle_file = {}
for afile in source:
if afile.upper().endswith(".VFR"):
middle_file.update({afile.split(".")[0]+".c":os.path.join(self.module_autogen.DebugDir,afile.split(".")[0]+".c")})
if afile.upper().endswith((".S","ASM")):
middle_file.update({afile.split(".")[0]+".i":os.path.join(self.module_autogen.OutputDir,afile.split(".")[0]+".i")})
if afile.upper().endswith(".ASL"):
middle_file.update({afile.split(".")[0]+".i":os.path.join(self.module_autogen.OutputDir,afile.split(".")[0]+".i")})
source.update({"AutoGen.c":os.path.join(self.module_autogen.OutputDir,"AutoGen.c")})
source.update(middle_file)
return source
@cached_property
def HasNamesakeSourceFile(self):
source_base_name = set([os.path.basename(item.File) for item in self.module_autogen.SourceFileList])
rt = len(source_base_name) != len(self.module_autogen.SourceFileList)
return rt
@cached_property
def CcPPCommandPathSet(self):
rt = set()
rt.add(self.module_autogen.BuildOption.get('CC',{}).get('PATH'))
rt.add(self.module_autogen.BuildOption.get('ASLCC',{}).get('PATH'))
rt.add(self.module_autogen.BuildOption.get('ASLPP',{}).get('PATH'))
rt.add(self.module_autogen.BuildOption.get('VFRPP',{}).get('PATH'))
rt.add(self.module_autogen.BuildOption.get('PP',{}).get('PATH'))
rt.add(self.module_autogen.BuildOption.get('APP',{}).get('PATH'))
rt.discard(None)
return rt
@cached_property
def TargetFileList(self):
""" Get a map of module's target name to a tuple of module's targets path and whose input file path """
targets = {}
targets["AutoGen.obj"] = (PathClass(os.path.join(self.module_autogen.OutputDir,"AutoGen.obj")),PathClass(os.path.join(self.module_autogen.DebugDir,"AutoGen.c")))
for item in self.module_autogen.Targets.values():
for block in item:
targets[block.Target.Path] = (block.Target,block.Inputs[0])
return targets
def GetRealTarget(self,source_file_abs):
""" Get the final target file based on source file abspath """
source_target_map = {item[1].Path:item[0].Path for item in self.TargetFileList.values()}
source_name_map = {item[1].File:item[0].Path for item in self.TargetFileList.values()}
target_abs = source_target_map.get(source_file_abs)
if target_abs is None:
if source_file_abs.strip().endswith(".i"):
sourcefilename = os.path.basename(source_file_abs.strip())
for sourcefile in source_name_map:
if sourcefilename.split(".")[0] == sourcefile.split(".")[0]:
target_abs = source_name_map[sourcefile]
break
else:
target_abs = source_file_abs
else:
target_abs = source_file_abs
return target_abs
def CreateDepsFileForMsvc(self, DepList):
""" Generate dependency files, .deps file from /showIncludes output message """
if not DepList:
return
ModuleDepDict = {}
current_source = ""
SourceFileAbsPathMap = self.SourceFileList
for line in DepList:
line = line.strip()
if self.HasNamesakeSourceFile:
for cc_cmd in self.CcPPCommandPathSet:
if cc_cmd in line:
if '''"'''+cc_cmd+'''"''' in line:
cc_options = line[len(cc_cmd)+2:].split()
else:
cc_options = line[len(cc_cmd):].split()
SourceFileAbsPathMap = {os.path.basename(item):item for item in cc_options if not item.startswith("/") and os.path.exists(item)}
if line in SourceFileAbsPathMap:
current_source = line
if current_source not in ModuleDepDict:
ModuleDepDict[SourceFileAbsPathMap[current_source]] = []
elif "Note: including file:" == line.lstrip()[:21]:
if not current_source:
EdkLogger.error("build",BUILD_ERROR, "Parse /showIncludes output failed. line: %s. \n" % line, RaiseError=False)
else:
ModuleDepDict[SourceFileAbsPathMap[current_source]].append(line.lstrip()[22:].strip())
for source_abs in ModuleDepDict:
if ModuleDepDict[source_abs]:
target_abs = self.GetRealTarget(source_abs)
dep_file_name = os.path.basename(source_abs) + ".deps"
SaveFileOnChange(os.path.join(os.path.dirname(target_abs),dep_file_name)," \\\n".join([target_abs+":"] + ['''"''' + item +'''"''' for item in ModuleDepDict[source_abs]]),False)
def UpdateDepsFileforNonMsvc(self):
""" Update .deps files.
1. Update target path to absolute path.
2. Update middle target to final target.
"""
for abspath in self.deps_files:
if abspath.endswith(".trim.deps"):
continue
try:
newcontent = []
with open(abspath,"r") as fd:
lines = fd.readlines()
if lines[-1] == DEP_FILE_TAIL:
continue
firstlineitems = lines[0].strip().split(" ")
if len(firstlineitems) > 2:
sourceitem = firstlineitems[1]
else:
sourceitem = lines[1].strip().split(" ")[0]
source_abs = self.SourceFileList.get(sourceitem,sourceitem)
firstlineitems[0] = self.GetRealTarget(source_abs)
p_target = firstlineitems
if not p_target[0].strip().endswith(":"):
p_target[0] += ": "
if len(p_target) == 2:
p_target[0] += lines[1]
newcontent.append(p_target[0])
newcontent.extend(lines[2:])
else:
line1 = " ".join(p_target).strip()
line1 += "\n"
newcontent.append(line1)
newcontent.extend(lines[1:])
newcontent.append("\n")
newcontent.append(DEP_FILE_TAIL)
with open(abspath,"w") as fw:
fw.write("".join(newcontent))
except Exception as e:
EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False)
continue
def UpdateDepsFileforTrim(self):
""" Update .deps file which generated by trim. """
for abspath in self.deps_files:
if not abspath.endswith(".trim.deps"):
continue
try:
newcontent = []
with open(abspath,"r") as fd:
lines = fd.readlines()
if lines[-1] == DEP_FILE_TAIL:
continue
source_abs = lines[0].strip().split(" ")[0]
targetitem = self.GetRealTarget(source_abs.strip(" :"))
targetitem += ": "
targetitem += lines[1]
newcontent.append(targetitem)
newcontent.extend(lines[2:])
newcontent.append("\n")
newcontent.append(DEP_FILE_TAIL)
with open(abspath,"w") as fw:
fw.write("".join(newcontent))
except Exception as e:
EdkLogger.error("build",FILE_NOT_FOUND, "%s doesn't exist" % abspath, ExtraData=str(e), RaiseError=False)
continue

View File

@ -1129,8 +1129,31 @@ class ModuleAutoGen(AutoGen):
for Inc in IncludesList: for Inc in IncludesList:
if Inc not in RetVal: if Inc not in RetVal:
RetVal.append(str(Inc)) RetVal.append(str(Inc))
RetVal.extend(self.IncPathFromBuildOptions)
return RetVal return RetVal
@cached_property
def IncPathFromBuildOptions(self):
IncPathList = []
for tool in self.BuildOption:
if 'FLAGS' in self.BuildOption[tool]:
flags = self.BuildOption[tool]['FLAGS']
whitespace = False
for flag in flags.split(" "):
flag = flag.strip()
if flag.startswith(("/I","-I")):
if len(flag)>2:
if os.path.exists(flag[2:]):
IncPathList.append(flag[2:])
else:
whitespace = True
continue
if whitespace and flag:
if os.path.exists(flag):
IncPathList.append(flag)
whitespace = False
return IncPathList
@cached_property @cached_property
def IncludePathLength(self): def IncludePathLength(self):
return sum(len(inc)+1 for inc in self.IncludePathList) return sum(len(inc)+1 for inc in self.IncludePathList)

View File

@ -57,7 +57,7 @@ from multiprocessing import Manager
from AutoGen.DataPipe import MemoryDataPipe from AutoGen.DataPipe import MemoryDataPipe
from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo, PlatformInfo from AutoGen.ModuleAutoGenHelper import WorkSpaceInfo, PlatformInfo
from GenFds.FdfParser import FdfParser from GenFds.FdfParser import FdfParser
from AutoGen.IncludesAutoGen import IncludesAutoGen
## standard targets of build command ## standard targets of build command
gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run'] gSupportedTarget = ['all', 'genc', 'genmake', 'modules', 'libraries', 'fds', 'clean', 'cleanall', 'cleanlib', 'run']
@ -175,18 +175,31 @@ def NormFile(FilePath, Workspace):
# @param To The stream message put on # @param To The stream message put on
# @param ExitFlag The flag used to indicate stopping reading # @param ExitFlag The flag used to indicate stopping reading
# #
def ReadMessage(From, To, ExitFlag): def ReadMessage(From, To, ExitFlag,MemTo=None):
while True: while True:
# read one line a time # read one line a time
Line = From.readline() Line = From.readline()
# empty string means "end" # empty string means "end"
if Line is not None and Line != b"": if Line is not None and Line != b"":
To(Line.rstrip().decode(encoding='utf-8', errors='ignore')) LineStr = Line.rstrip().decode(encoding='utf-8', errors='ignore')
if MemTo is not None:
if "Note: including file:" == LineStr.lstrip()[:21]:
MemTo.append(LineStr)
else:
To(LineStr)
MemTo.append(LineStr)
else:
To(LineStr)
else: else:
break break
if ExitFlag.isSet(): if ExitFlag.isSet():
break break
class MakeSubProc(Popen):
def __init__(self,*args, **argv):
super(MakeSubProc,self).__init__(*args, **argv)
self.ProcOut = []
## Launch an external program ## Launch an external program
# #
# This method will call subprocess.Popen to execute an external program with # This method will call subprocess.Popen to execute an external program with
@ -197,7 +210,7 @@ def ReadMessage(From, To, ExitFlag):
# @param Command A list or string containing the call of the program # @param Command A list or string containing the call of the program
# @param WorkingDir The directory in which the program will be running # @param WorkingDir The directory in which the program will be running
# #
def LaunchCommand(Command, WorkingDir): def LaunchCommand(Command, WorkingDir,ModuleAuto = None):
BeginTime = time.time() BeginTime = time.time()
# if working directory doesn't exist, Popen() will raise an exception # if working directory doesn't exist, Popen() will raise an exception
if not os.path.isdir(WorkingDir): if not os.path.isdir(WorkingDir):
@ -216,19 +229,19 @@ def LaunchCommand(Command, WorkingDir):
EndOfProcedure = None EndOfProcedure = None
try: try:
# launch the command # launch the command
Proc = Popen(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True) Proc = MakeSubProc(Command, stdout=PIPE, stderr=PIPE, env=os.environ, cwd=WorkingDir, bufsize=-1, shell=True)
# launch two threads to read the STDOUT and STDERR # launch two threads to read the STDOUT and STDERR
EndOfProcedure = Event() EndOfProcedure = Event()
EndOfProcedure.clear() EndOfProcedure.clear()
if Proc.stdout: if Proc.stdout:
StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure)) StdOutThread = Thread(target=ReadMessage, args=(Proc.stdout, EdkLogger.info, EndOfProcedure,Proc.ProcOut))
StdOutThread.setName("STDOUT-Redirector") StdOutThread.setName("STDOUT-Redirector")
StdOutThread.setDaemon(False) StdOutThread.setDaemon(False)
StdOutThread.start() StdOutThread.start()
if Proc.stderr: if Proc.stderr:
StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure)) StdErrThread = Thread(target=ReadMessage, args=(Proc.stderr, EdkLogger.quiet, EndOfProcedure,Proc.ProcOut))
StdErrThread.setName("STDERR-Redirector") StdErrThread.setName("STDERR-Redirector")
StdErrThread.setDaemon(False) StdErrThread.setDaemon(False)
StdErrThread.start() StdErrThread.start()
@ -263,6 +276,15 @@ def LaunchCommand(Command, WorkingDir):
EdkLogger.info(RespContent) EdkLogger.info(RespContent)
EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir)) EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % (Command, WorkingDir))
if ModuleAuto:
iau = IncludesAutoGen(WorkingDir,ModuleAuto)
if ModuleAuto.ToolChainFamily == TAB_COMPILER_MSFT:
iau.CreateDepsFileForMsvc(Proc.ProcOut)
else:
iau.UpdateDepsFileforNonMsvc()
iau.UpdateDepsFileforTrim()
iau.CreateModuleDeps()
iau.CreateDepsInclude()
return "%dms" % (int(round((time.time() - BeginTime) * 1000))) return "%dms" % (int(round((time.time() - BeginTime) * 1000)))
## The smallest unit that can be built in multi-thread build mode ## The smallest unit that can be built in multi-thread build mode
@ -608,7 +630,7 @@ class BuildTask:
# #
def _CommandThread(self, Command, WorkingDir): def _CommandThread(self, Command, WorkingDir):
try: try:
self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir) self.BuildItem.BuildObject.BuildTime = LaunchCommand(Command, WorkingDir,self.BuildItem.BuildObject)
self.CompleteFlag = True self.CompleteFlag = True
# Run hash operation post dependency, to account for libs # Run hash operation post dependency, to account for libs
@ -1276,19 +1298,32 @@ class Build():
# build library # build library
if Target == 'libraries': if Target == 'libraries':
for Lib in AutoGenObject.LibraryBuildDirectoryList: DirList = []
for Lib in AutoGenObject.LibraryAutoGenList:
if not Lib.IsBinaryModule:
DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))
for Lib, LibAutoGen in DirList:
NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild'] NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)
return True return True
# build module # build module
if Target == 'modules': if Target == 'modules':
for Lib in AutoGenObject.LibraryBuildDirectoryList: DirList = []
for Lib in AutoGenObject.LibraryAutoGenList:
if not Lib.IsBinaryModule:
DirList.append((os.path.join(AutoGenObject.BuildDir, Lib.BuildDir),Lib))
for Lib, LibAutoGen in DirList:
NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild'] NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Lib, makefile)), 'pbuild']
LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,LibAutoGen)
for Mod in AutoGenObject.ModuleBuildDirectoryList:
DirList = []
for ModuleAutoGen in AutoGenObject.ModuleAutoGenList:
if not ModuleAutoGen.IsBinaryModule:
DirList.append((os.path.join(AutoGenObject.BuildDir, ModuleAutoGen.BuildDir),ModuleAutoGen))
for Mod,ModAutoGen in DirList:
NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild'] NewBuildCommand = BuildCommand + ['-f', os.path.normpath(os.path.join(Mod, makefile)), 'pbuild']
LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir) LaunchCommand(NewBuildCommand, AutoGenObject.MakeFileDir,ModAutoGen)
self.CreateAsBuiltInf() self.CreateAsBuiltInf()
if GlobalData.gBinCacheDest: if GlobalData.gBinCacheDest:
self.UpdateBuildCache() self.UpdateBuildCache()