Reviewed-by: Liming Gao <[email protected]>
> -----Original Message----- > From: edk2-devel [mailto:[email protected]] On Behalf Of > Yonghong Zhu > Sent: Wednesday, March 16, 2016 11:09 AM > To: [email protected] > Subject: [edk2] [Patch] BaseTools: Fix nmake failure due to command-line > length limitation > > NMAKE is limited to command-line length of 4096 characters. Due to the > large number of /I directives specified on command line (one per include > directory), the path length of WORKSPACE is multiplied by the number of > /I directives and can exceed the limit. > This patch: > 1. Add new build option -l, --cmd-len to set the maximum command line > length, default value is 4096. > 2. Generate the response file only if the command line length exceed its > maximum characters (default is 4096) when build the module. Cover > PP_FLAGS, CC_FLAGS, VFRPP_FLAGS, APP_FLAGS, ASLPP_FLAGS, > ASLCC_FLAGS and > ASM_FLAGS. > 3. The content of the response file is combine from the FLAGS option and > INC option. > 4. When build failure, it would print out the response file's file > location and its content. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Yonghong Zhu <[email protected]> > --- > BaseTools/Source/Python/AutoGen/AutoGen.py | 9 +++ > BaseTools/Source/Python/AutoGen/GenMake.py | 114 > ++++++++++++++++++++++++++- > BaseTools/Source/Python/Common/GlobalData.py | 2 +- > BaseTools/Source/Python/build/build.py | 12 +++ > 4 files changed, 135 insertions(+), 2 deletions(-) > > diff --git a/BaseTools/Source/Python/AutoGen/AutoGen.py > b/BaseTools/Source/Python/AutoGen/AutoGen.py > index c7aa84f..4934c57 100644 > --- a/BaseTools/Source/Python/AutoGen/AutoGen.py > +++ b/BaseTools/Source/Python/AutoGen/AutoGen.py > @@ -2376,10 +2376,11 @@ class ModuleAutoGen(AutoGen): > self._OutputDir = None > self._DebugDir = None > self._MakeFileDir = None > > self._IncludePathList = None > + self._IncludePathLength = 0 > self._AutoGenFileList = None > self._UnicodeFileList = None > self._SourceFileList = None > self._ObjectFileList = None > self._BinaryFileList = None > @@ -3222,10 +3223,17 @@ class ModuleAutoGen(AutoGen): > for Inc in Package.Includes: > if Inc not in self._IncludePathList: > self._IncludePathList.append(str(Inc)) > return self._IncludePathList > > + def _GetIncludePathLength(self): > + self._IncludePathLength = 0 > + if self._IncludePathList: > + for inc in self._IncludePathList: > + self._IncludePathLength += len(' ' + inc) > + return self._IncludePathLength > + > ## 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. > @@ -3814,10 +3822,11 @@ class ModuleAutoGen(AutoGen): > DebugDir = property(_GetDebugDir) > MakeFileDir = property(_GetMakeFileDir) > CustomMakefile = property(_GetCustomMakefile) > > IncludePathList = property(_GetIncludePathList) > + IncludePathLength = property(_GetIncludePathLength) > AutoGenFileList = property(_GetAutoGenFileList) > UnicodeFileList = property(_GetUnicodeFileList) > SourceFileList = property(_GetSourceFileList) > BinaryFileList = property(_GetBinaryFiles) # FileType : [File List] > Targets = property(_GetTargets) > diff --git a/BaseTools/Source/Python/AutoGen/GenMake.py > b/BaseTools/Source/Python/AutoGen/GenMake.py > index ec24c70..5543aaa 100644 > --- a/BaseTools/Source/Python/AutoGen/GenMake.py > +++ b/BaseTools/Source/Python/AutoGen/GenMake.py > @@ -1,9 +1,9 @@ > ## @file > # Create makefile for MS nmake and GNU make > # > -# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR> > +# Copyright (c) 2007 - 2016, Intel Corporation. All rights reserved.<BR> > # This program and the accompanying materials > # are licensed and made available under the terms and conditions of the BSD > License > # which accompanies this distribution. The full text of the license may be > found at > # http://opensource.org/licenses/bsd-license.php > # > @@ -495,10 +495,26 @@ cleanlib: > if Attr == "FLAGS": > Value = RemoveDupOption(Value, IncPrefix, > self._AutoGenObject.IncludePathList) > ToolsDef.append("%s_%s = %s" % (Tool, Attr, Value)) > ToolsDef.append("") > > + # generate the Response file and Response flag > + RespDict = self.CommandExceedLimit() > + RespFileList = os.path.join(self._AutoGenObject.OutputDir, > 'respfilelist.txt') > + if RespDict: > + RespFileListContent = '' > + for Resp in RespDict.keys(): > + RespFile = os.path.join(self._AutoGenObject.OutputDir, > str(Resp).lower() + '.txt') > + SaveFileOnChange(RespFile, RespDict[Resp], False) > + ToolsDef.append("%s = %s" % (Resp, '@' + RespFile)) > + RespFileListContent += '@' + RespFile + os.linesep > + RespFileListContent += RespDict[Resp] + os.linesep > + SaveFileOnChange(RespFileList, RespFileListContent, False) > + else: > + if os.path.exists(RespFileList): > + os.remove(RespFileList) > + > # convert source files and binary files to build targets > self.ResultFileList = [str(T.Target) for T in > self._AutoGenObject.CodaTargetList] > if len(self.ResultFileList) == 0 and > len(self._AutoGenObject.SourceFileList) <> 0: > EdkLogger.error("build", AUTOGEN_ERROR, "Nothing to build", > ExtraData="[%s]" % str(self._AutoGenObject)) > @@ -618,10 +634,106 @@ cleanlib: > "backward_compatible_target": BcTargetList, > } > > return MakefileTemplateDict > > + def CommandExceedLimit(self): > + FlagDict = { > + 'CC' : { 'Macro' : '$(CC_FLAGS)', 'Value' : > False}, > + 'PP' : { 'Macro' : '$(PP_FLAGS)', 'Value' : > False}, > + 'APP' : { 'Macro' : '$(APP_FLAGS)', 'Value' : > False}, > + 'ASLPP' : { 'Macro' : '$(ASLPP_FLAGS)', 'Value' : > False}, > + 'VFRPP' : { 'Macro' : '$(VFRPP_FLAGS)', 'Value' : > False}, > + 'ASM' : { 'Macro' : '$(ASM_FLAGS)', 'Value' : > False}, > + 'ASLCC' : { 'Macro' : '$(ASLCC_FLAGS)', 'Value' : > False}, > + } > + > + RespDict = {} > + FileTypeList = [] > + IncPrefix = self._INC_FLAG_[self._AutoGenObject.ToolChainFamily] > + > + # base on the source files to decide the file type > + for File in self._AutoGenObject.SourceFileList: > + for type in self._AutoGenObject.FileTypes: > + if File in self._AutoGenObject.FileTypes[type]: > + if type not in FileTypeList: > + FileTypeList.append(type) > + > + # calculate the command-line length > + if FileTypeList: > + for type in FileTypeList: > + BuildTargets = > self._AutoGenObject.BuildRules[type].BuildTargets > + for Target in BuildTargets: > + CommandList = BuildTargets[Target].Commands > + for SingleCommand in CommandList: > + Tool = '' > + SingleCommandLength = len(SingleCommand) > + SingleCommandList = SingleCommand.split() > + if len(SingleCommandList) > 0: > + for Flag in FlagDict.keys(): > + if '$('+ Flag +')' in SingleCommandList[0]: > + Tool = Flag > + break > + if Tool: > + SingleCommandLength += > len(self._AutoGenObject._BuildOption[Tool]['PATH']) > + for item in SingleCommandList[1:]: > + if FlagDict[Tool]['Macro'] in item: > + Str = > self._AutoGenObject._BuildOption[Tool]['FLAGS'] > + while(Str.find('$(') != -1): > + for macro in > self._AutoGenObject.Macros.keys(): > + MacroName = '$('+ macro + ')' > + if (Str.find(MacroName) != -1): > + Str = Str.replace(MacroName, > self._AutoGenObject.Macros[macro]) > + break > + else: > + EdkLogger.error("build", > AUTOGEN_ERROR, "Not > supported macro is found in make command : %s" % Str, ExtraData="[%s]" % > str(self._AutoGenObject)) > + SingleCommandLength += len(Str) > + elif '$(INC)' in item: > + SingleCommandLength += > self._AutoGenObject.IncludePathLength + len(IncPrefix) * > len(self._AutoGenObject._IncludePathList) > + elif item.find('$(') != -1: > + Str = item > + for Option in > self._AutoGenObject.BuildOption.keys(): > + for Attr in > self._AutoGenObject.BuildOption[Option]: > + if Str.find(Option + '_' + Attr) > != -1: > + Str = Str.replace('$(' + > Option + '_' + Attr + ')', > self._AutoGenObject.BuildOption[Option][Attr]) > + while(Str.find('$(') != -1): > + for macro in > self._AutoGenObject.Macros.keys(): > + MacroName = '$('+ macro + ')' > + if (Str.find(MacroName) != -1): > + Str = Str.replace(MacroName, > self._AutoGenObject.Macros[macro]) > + break > + else: > + EdkLogger.error("build", > AUTOGEN_ERROR, "Not > supported macro is found in make command : %s" % Str, ExtraData="[%s]" % > str(self._AutoGenObject)) > + > + SingleCommandLength += len(Str) > + > + if SingleCommandLength > > GlobalData.gCommandMaxLength: > + FlagDict[Tool]['Value'] = True > + > + # generate the response file content by combine the FLAGS and > INC > + for Flag in FlagDict.keys(): > + if FlagDict[Flag]['Value']: > + Key = Flag + '_RESP' > + RespMacro = FlagDict[Flag]['Macro'].replace('FLAGS', > 'RESP') > + Value = > self._AutoGenObject.BuildOption[Flag]['FLAGS'] > + for inc in self._AutoGenObject._IncludePathList: > + Value += ' ' + IncPrefix + inc > + while (Value.find('$(') != -1): > + for macro in self._AutoGenObject.Macros.keys(): > + MacroName = '$('+ macro + ')' > + if (Value.find(MacroName) != -1): > + Value = Value.replace(MacroName, > self._AutoGenObject.Macros[macro]) > + break > + else: > + EdkLogger.error("build", AUTOGEN_ERROR, "Not > supported macro is found in make command : %s" % Str, ExtraData="[%s]" % > str(self._AutoGenObject)) > + RespDict[Key] = Value > + for Target in BuildTargets: > + for i, SingleCommand in > enumerate(BuildTargets[Target].Commands): > + if FlagDict[Flag]['Macro'] in SingleCommand: > + BuildTargets[Target].Commands[i] = > SingleCommand.replace('$(INC)','').replace(FlagDict[Flag]['Macro'], > RespMacro) > + return RespDict > + > def ProcessBuildTargetList(self): > # > # Search dependency file list for each source file > # > ForceIncludedFile = [] > diff --git a/BaseTools/Source/Python/Common/GlobalData.py > b/BaseTools/Source/Python/Common/GlobalData.py > index 4234bf5..8f544bd 100644 > --- a/BaseTools/Source/Python/Common/GlobalData.py > +++ b/BaseTools/Source/Python/Common/GlobalData.py > @@ -32,11 +32,11 @@ gPlatformPcds = {} > gPlatformOtherPcds = {} > gActivePlatform = None > gCommandLineDefines = {} > gEdkGlobal = {} > gOverrideDir = {} > - > +gCommandMaxLength = 4096 > # for debug trace purpose when problem occurs > gProcessingFile = '' > gBuildingModule = '' > > ## Regular expression for matching macro used in DSC/DEC/INF file inclusion > diff --git a/BaseTools/Source/Python/build/build.py > b/BaseTools/Source/Python/build/build.py > index 5619638..1607928 100644 > --- a/BaseTools/Source/Python/build/build.py > +++ b/BaseTools/Source/Python/build/build.py > @@ -302,10 +302,18 @@ def LaunchCommand(Command, WorkingDir): > > # check the return code of the program > if Proc.returncode != 0: > if type(Command) != type(""): > Command = " ".join(Command) > + # print out the Response file and its content when make failure > + RespFile = os.path.join(WorkingDir, 'OUTPUT', 'respfilelist.txt') > + if os.path.isfile(RespFile): > + f = open(RespFile) > + RespContent = f.read() > + f.close() > + EdkLogger.info(RespContent) > + > EdkLogger.error("build", COMMAND_FAILURE, ExtraData="%s [%s]" % > (Command, WorkingDir)) > > ## The smallest unit that can be built in multi-thread build mode > # > # This is the base class of build unit. The "Obj" parameter must provide > @@ -773,10 +781,13 @@ class Build(): > self.Platform = None > self.LoadFixAddress = 0 > self.UniFlag = BuildOptions.Flag > self.BuildModules = [] > > + if BuildOptions.CommandLength: > + GlobalData.gCommandMaxLength = BuildOptions.CommandLength > + > # print dot character during doing some time-consuming work > self.Progress = Utils.Progressor() > > self.InitBuild() > > @@ -1929,10 +1940,11 @@ def MyOptionParser(): > Parser.add_option("-N", "--no-cache", action="store_true", > dest="DisableCache", default=False, help="Disable build cache mechanism") > Parser.add_option("--conf", action="store", type="string", > dest="ConfDirectory", help="Specify the customized Conf directory.") > Parser.add_option("--check-usage", action="store_true", > dest="CheckUsage", default=False, help="Check usage content of entries > listed in INF file.") > Parser.add_option("--ignore-sources", action="store_true", > dest="IgnoreSources", default=False, help="Focus to a binary build and > ignore all source files") > Parser.add_option("--pcd", action="append", dest="OptionPcd", > help="Set PCD value by command line. Format: 'PcdName=Value' ") > + Parser.add_option("-l", "--cmd-len", action="store", type="int", > dest="CommandLength", help="Specify the maximum line length of build > command. Default is 4096.") > > (Opt, Args) = Parser.parse_args() > return (Opt, Args) > > ## Tool entrance method > -- > 2.6.1.windows.1 > > _______________________________________________ > edk2-devel mailing list > [email protected] > https://lists.01.org/mailman/listinfo/edk2-devel _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

