Hi,
When a response file (a file containing arguments to a program, one per line)
is given to the driver for a final link, very long command lines can be
constructed for the linker. In some cases, these command lines are too long,
and the OS will fail to execute the linker.
The attached patch fixes this issue by simply using a response file all the
time for passing arguments to the linker. Alternate strategies include only
using a response file if a response file was used on the original command line
or using a response file if the size of the arguments exceeds some limit. I
didn't go with the former because it seemed too use-case specific (and will not
correctly handle cases where response files aren't used to pass arguments to
the driver and you still need a response file for the linker) and I didn't go
with the latter because any cross-platform limit is going to be necessarily
conservative and you might as well just use a response file all the time at
that point.
I realize this adds a small cost to every link. Alternate ideas welcome.
The patch changes all the linking jobs to use the new AddLinkerJob function. I
used my best judgement as to whether response files were supported, but I may
have missed some cases.
-Nathan
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 62b1feb..7bee03b 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -187,6 +187,56 @@ static void AddLinkerInputs(const ToolChain &TC,
addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");
}
+// Write the strings in CmdArgs to a temporary file. If successful, return
+// true and write the name of the temporary file to Filename. Otherwise,
+// return false.
+static bool WriteResponseFile(const Driver &D, const ArgStringList &CmdArgs,
+ std::string &Filename)
+{
+ std::string TmpPath = D.GetTemporaryPath("response-file", ".tmp");
+ llvm::sys::Path P(TmpPath);
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream OS(TmpPath.c_str(), ErrorInfo,
+ llvm::raw_fd_ostream::F_Binary);
+ if (!ErrorInfo.empty()) {
+ return false;
+ }
+
+ for (ArgStringList::const_iterator it = CmdArgs.begin(), ie = CmdArgs.end();
+ it != ie; ++it) {
+ OS << *it << '\n';
+ }
+ OS.close();
+ if (OS.has_error()) {
+ P.eraseFromDisk();
+ return false;
+ }
+
+ Filename = TmpPath;
+ return true;
+}
+
+static void AddLinkerJob(Compilation &C, const JobAction &JA,
+ const Tool &T, const ArgList &Args,
+ const ArgStringList &CmdArgs,
+ const char *LinkerProgramName,
+ bool SupportsResponseFiles)
+{
+ const ToolChain &TC = T.getToolChain();
+ const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerProgramName));
+ if (SupportsResponseFiles) {
+ std::string ResponseFile;
+ if (WriteResponseFile(TC.getDriver(), CmdArgs, ResponseFile)) {
+ ArgStringList AlternateArgs;
+ std::string FileArg = "@" + ResponseFile;
+ AlternateArgs.push_back(Args.MakeArgString(FileArg.c_str()));
+ C.addCommand(new Command(JA, T, Exec, AlternateArgs));
+ return;
+ }
+ }
+ C.addCommand(new Command(JA, T, Exec, CmdArgs));
+}
+
/// \brief Determine whether Objective-C automated reference counting is
/// enabled.
static bool isObjCAutoRefCount(const ArgList &Args) {
@@ -3978,11 +4028,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const
JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(StartFilesDir + finiObj));
}
- std::string Linker = ToolChain.GetProgramPath("hexagon-ld");
- C.addCommand(
- new Command(
- JA, *this,
- Args.MakeArgString(Linker), CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "hexagon-ld", false);
}
// Hexagon tools end.
@@ -4550,9 +4596,7 @@ void darwin::Link::ConstructJob(Compilation &C, const
JobAction &JA,
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_F);
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JS, *this, Args, CmdArgs, "ld", true);
}
void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
@@ -4747,10 +4791,7 @@ void solaris::Link::ConstructJob(Compilation &C, const
JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(LibPath + "crtn.o"));
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", false);
}
void auroraux::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -4859,10 +4900,7 @@ void auroraux::Link::ConstructJob(Compilation &C, const
JobAction &JA,
}
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", false);
}
void openbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5008,9 +5046,7 @@ void openbsd::Link::ConstructJob(Compilation &C, const
JobAction &JA,
getToolChain().GetFilePath("crtendS.o")));
}
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", true);
}
void bitrig::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5150,9 +5186,7 @@ void bitrig::Link::ConstructJob(Compilation &C, const
JobAction &JA,
getToolChain().GetFilePath("crtendS.o")));
}
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", false);
}
void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5399,10 +5433,7 @@ void freebsd::Link::ConstructJob(Compilation &C, const
JobAction &JA,
}
addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple());
-
- const char *Exec =
- Args.MakeArgString(ToolChain.GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", true);
}
void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5549,9 +5580,7 @@ void netbsd::Link::ConstructJob(Compilation &C, const
JobAction &JA,
}
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", true);
}
void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -5941,8 +5970,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const
JobAction &JA,
}
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
- C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", true);
}
void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6019,8 +6047,7 @@ void minix::Link::ConstructJob(Compilation &C, const
JobAction &JA,
Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
}
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", false);
}
/// DragonFly Tools
@@ -6174,10 +6201,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const
JobAction &JA,
}
addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple());
-
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("ld"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "ld", true);
}
void visualstudio::Link::ConstructJob(Compilation &C, const JobAction &JA,
@@ -6210,7 +6234,5 @@ void visualstudio::Link::ConstructJob(Compilation &C,
const JobAction &JA,
CmdArgs.push_back(it->getFilename());
}
- const char *Exec =
- Args.MakeArgString(getToolChain().GetProgramPath("link.exe"));
- C.addCommand(new Command(JA, *this, Exec, CmdArgs));
+ AddLinkerJob(C, JA, *this, Args, CmdArgs, "link.exe", true);
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits