16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringRef.h"
20 #include "llvm/ADT/StringSet.h"
21 #include "llvm/ADT/StringSwitch.h"
22 #include "llvm/Support/CrashRecoveryContext.h"
23 #include "llvm/Support/FileSystem.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/PrettyStackTrace.h"
26 #include "llvm/Support/Program.h"
27 #include "llvm/Support/raw_ostream.h"
32 #include <system_error>
35 using namespace clang;
36 using namespace driver;
40 const llvm::opt::ArgStringList &Arguments,
42 : Source(Source), Creator(Creator), ResponseSupport(ResponseSupport),
43 Executable(Executable), Arguments(Arguments) {
44 for (
const auto &II : Inputs)
47 for (
const auto &II : Outputs)
49 OutputFilenames.push_back(II.getFilename());
55 static bool skipArgs(
const char *Flag,
bool HaveCrashVFS,
int &SkipNum,
60 bool ShouldSkip = llvm::StringSwitch<bool>(Flag)
61 .Cases(
"-MF",
"-MT",
"-MQ",
"-serialize-diagnostic-file",
true)
62 .Cases(
"-o",
"-dependency-file",
true)
63 .Cases(
"-fdebug-compilation-dir",
"-diagnostic-log-file",
true)
64 .Cases(
"-dwarf-debug-flags",
"-ivfsoverlay",
true)
70 IsInclude = llvm::StringSwitch<bool>(Flag)
71 .Cases(
"-include",
"-header-include-file",
true)
72 .Cases(
"-idirafter",
"-internal-isystem",
"-iwithprefix",
true)
73 .Cases(
"-internal-externc-isystem",
"-iprefix",
true)
74 .Cases(
"-iwithprefixbefore",
"-isystem",
"-iquote",
true)
75 .Cases(
"-isysroot",
"-I",
"-F",
"-resource-dir",
true)
76 .Cases(
"-iframework",
"-include-pch",
true)
84 ShouldSkip = llvm::StringSwitch<bool>(Flag)
85 .Cases(
"-M",
"-MM",
"-MG",
"-MP",
"-MD",
true)
95 StringRef FlagRef(Flag);
96 IsInclude = FlagRef.startswith(
"-F") || FlagRef.startswith(
"-I");
99 if (FlagRef.startswith(
"-fmodules-cache-path="))
106 void Command::writeResponseFile(raw_ostream &OS)
const {
109 for (
const auto *Arg : InputFileList) {
118 for (
const auto *Arg : Arguments) {
121 for (; *Arg !=
'\0'; Arg++) {
122 if (*Arg ==
'\"' || *Arg ==
'\\') {
132 void Command::buildArgvForResponseFile(
138 Out.push_back(Executable);
139 Out.push_back(ResponseFileFlag.c_str());
143 llvm::StringSet<> Inputs;
144 for (
const auto *InputName : InputFileList)
145 Inputs.insert(InputName);
146 Out.push_back(Executable);
149 bool FirstInput =
true;
150 for (
const auto *Arg : Arguments) {
151 if (Inputs.count(Arg) == 0) {
153 }
else if (FirstInput) {
156 Out.push_back(ResponseFile);
166 using namespace llvm;
170 if (path::is_absolute(InInc))
172 std::error_code EC = fs::current_path(OutInc);
175 path::append(OutInc, InInc);
181 StringRef FlagRef(Args[Idx + NumArgs - 1]);
182 assert((FlagRef.startswith(
"-F") || FlagRef.startswith(
"-I")) &&
183 "Expecting -I or -F");
184 StringRef Inc = FlagRef.slice(2, StringRef::npos);
185 if (getAbsPath(Inc, NewInc)) {
188 IncFlags.push_back(std::move(NewArg));
193 assert(NumArgs == 2 &&
"Not expecting more than two arguments");
194 StringRef Inc(Args[Idx + NumArgs - 1]);
195 if (!getAbsPath(Inc, NewInc))
198 IncFlags.push_back(std::move(NewInc));
205 llvm::sys::printArg(OS, Executable,
true);
209 if (ResponseFile !=
nullptr) {
210 buildArgvForResponseFile(ArgsRespFile);
214 bool HaveCrashVFS = CrashInfo && !CrashInfo->
VFSPath.empty();
215 for (
size_t i = 0, e = Args.size(); i < e; ++i) {
216 const char *
const Arg = Args[i];
220 bool IsInclude =
false;
221 if (
skipArgs(Arg, HaveCrashVFS, NumArgs, IsInclude)) {
227 if (HaveCrashVFS && IsInclude) {
230 if (!NewIncFlags.empty()) {
231 for (
auto &F : NewIncFlags) {
233 llvm::sys::printArg(OS, F.c_str(), Quote);
244 (i == 0 || StringRef(Args[i - 1]) !=
"-main-file-name")) {
247 StringRef ShortName = llvm::sys::path::filename(CrashInfo->
Filename);
248 llvm::sys::printArg(OS, ShortName.str(), Quote);
254 llvm::sys::printArg(OS, Arg, Quote);
257 if (CrashInfo && HaveCrashVFS) {
259 llvm::sys::printArg(OS,
"-ivfsoverlay", Quote);
261 llvm::sys::printArg(OS, CrashInfo->
VFSPath.str(), Quote);
269 llvm::sys::path::parent_path(CrashInfo->
VFSPath));
270 llvm::sys::path::append(RelModCacheDir,
"repro-modules");
272 std::string ModCachePath =
"-fmodules-cache-path=";
273 ModCachePath.append(RelModCacheDir.c_str());
276 llvm::sys::printArg(OS, ModCachePath, Quote);
279 if (ResponseFile !=
nullptr) {
280 OS <<
"\n Arguments passed via response file:\n";
281 writeResponseFile(OS);
286 OS <<
" (end of response file)";
293 ResponseFile = FileName;
294 ResponseFileFlag = ResponseSupport.ResponseFlag;
295 ResponseFileFlag += FileName;
299 Environment.reserve(NewEnvironment.size() + 1);
300 Environment.assign(NewEnvironment.begin(), NewEnvironment.end());
301 Environment.push_back(
nullptr);
305 if (PrintInputFilenames) {
307 llvm::outs() << llvm::sys::path::filename(Arg.getFilename()) <<
"\n";
308 llvm::outs().flush();
313 std::string *ErrMsg,
bool *ExecutionFailed)
const {
317 if (ResponseFile ==
nullptr) {
318 Argv.push_back(Executable);
319 Argv.append(Arguments.begin(), Arguments.end());
320 Argv.push_back(
nullptr);
324 llvm::raw_string_ostream SS(RespContents);
327 writeResponseFile(SS);
328 buildArgvForResponseFile(Argv);
329 Argv.push_back(
nullptr);
333 if (std::error_code EC = writeFileWithEncoding(
334 ResponseFile, RespContents, ResponseSupport.ResponseEncoding)) {
336 *ErrMsg = EC.message();
338 *ExecutionFailed =
true;
346 std::vector<StringRef> ArgvVectorStorage;
347 if (!Environment.empty()) {
348 assert(Environment.back() ==
nullptr &&
349 "Environment vector should be null-terminated by now");
350 ArgvVectorStorage = llvm::toStringRefArray(Environment.data());
351 Env = makeArrayRef(ArgvVectorStorage);
354 auto Args = llvm::toStringRefArray(Argv.data());
355 return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects,
357 ErrMsg, ExecutionFailed, &ProcStat);
362 const char *Executable,
363 const llvm::opt::ArgStringList &Arguments,
365 :
Command(Source, Creator, ResponseSupport, Executable, Arguments, Inputs,
373 OS <<
" (in-process)\n";
378 std::string *ErrMsg,
bool *ExecutionFailed)
const {
390 Argv.push_back(
nullptr);
397 *ExecutionFailed =
false;
399 llvm::CrashRecoveryContext CRC;
400 CRC.DumpStackAndCleanupOnFailure =
true;
402 const void *PrettyState = llvm::SavePrettyStackState();
407 if (!CRC.RunSafely([&]() { R = D.CC1Main(Argv); })) {
408 llvm::RestorePrettyStackState(PrettyState);
417 "The CC1Command doesn't support changing the environment vars!");
425 :
Command(Source_, Creator_, ResponseSupport, Executable_, Arguments_,
431 OS <<
" || (exit 0)" << Terminator;
436 bool *ExecutionFailed)
const {
440 *ExecutionFailed =
false;
446 for (
const auto &Job : *
this)
447 Job.Print(OS, Terminator, Quote, CrashInfo);