19 #include "clang/Driver/Driver.h"
20 #include "clang/Basic/DiagnosticOptions.h"
21 #include "clang/Basic/HeaderInclude.h"
22 #include "clang/Basic/Stack.h"
23 #include "clang/Config/config.h"
24 #include "clang/Driver/Compilation.h"
25 #include "clang/Driver/DriverDiagnostic.h"
26 #include "clang/Driver/Options.h"
27 #include "clang/Driver/ToolChain.h"
28 #include "clang/Frontend/ChainedDiagnosticConsumer.h"
29 #include "clang/Frontend/CompilerInvocation.h"
30 #include "clang/Frontend/SerializedDiagnosticPrinter.h"
31 #include "clang/Frontend/TextDiagnosticPrinter.h"
32 #include "clang/Frontend/Utils.h"
33 #include "llvm/ADT/ArrayRef.h"
34 #include "llvm/ADT/SmallString.h"
35 #include "llvm/ADT/SmallVector.h"
36 #include "llvm/Option/ArgList.h"
37 #include "llvm/Option/OptTable.h"
38 #include "llvm/Option/Option.h"
39 #include "llvm/Support/BuryPointer.h"
40 #include "llvm/Support/CommandLine.h"
41 #include "llvm/Support/CrashRecoveryContext.h"
42 #include "llvm/Support/ErrorHandling.h"
43 #include "llvm/Support/FileSystem.h"
44 #include "llvm/Support/Host.h"
45 #include "llvm/Support/InitLLVM.h"
46 #include "llvm/Support/Path.h"
47 #include "llvm/Support/PrettyStackTrace.h"
48 #include "llvm/Support/Process.h"
49 #include "llvm/Support/Program.h"
50 #include "llvm/Support/Regex.h"
51 #include "llvm/Support/Signals.h"
52 #include "llvm/Support/StringSaver.h"
53 #include "llvm/Support/TargetSelect.h"
54 #include "llvm/Support/Timer.h"
55 #include "llvm/Support/raw_ostream.h"
59 #include <system_error>
60 using namespace clang;
61 using namespace clang::driver;
62 using namespace llvm::opt;
64 std::string GetExecutablePath(
const char *Argv0,
bool CanonicalPrefixes) {
65 if (!CanonicalPrefixes) {
66 SmallString<128> ExecutablePath(Argv0);
68 if (!llvm::sys::fs::exists(ExecutablePath))
69 if (llvm::ErrorOr<std::string> P = llvm::sys::findProgramByName(ExecutablePath))
71 return std::string(ExecutablePath.str());
76 void *P = (
void *)(intptr_t)GetExecutablePath;
77 return llvm::sys::fs::getMainExecutable(Argv0, P);
80 static const char *GetStableCStr(std::set<std::string> &SavedStrings, StringRef S) {
81 return SavedStrings.insert(std::string(S)).first->c_str();
111 static void ApplyOneQAOverride(raw_ostream &OS,
112 SmallVectorImpl<const char *> &Args,
114 std::set<std::string> &SavedStrings) {
117 if (Edit[0] ==
'^') {
118 const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
119 OS <<
"### Adding argument " << Str <<
" at beginning\n";
120 Args.insert(Args.begin() + 1, Str);
121 }
else if (Edit[0] ==
'+') {
122 const char *Str = GetStableCStr(SavedStrings, Edit.substr(1));
123 OS <<
"### Adding argument " << Str <<
" at end\n";
125 }
else if (Edit[0] ==
's' && Edit[1] ==
'/' && Edit.endswith(
"/") && Edit.slice(2, Edit.size() - 1).contains(
'/')) {
126 StringRef MatchPattern = Edit.substr(2).split(
'/').first;
127 StringRef ReplPattern = Edit.substr(2).split(
'/').second;
128 ReplPattern = ReplPattern.slice(0, ReplPattern.size() - 1);
130 for (
unsigned i = 1, e = Args.size(); i != e; ++i) {
132 if (Args[i] ==
nullptr)
134 std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
136 if (Repl != Args[i]) {
137 OS <<
"### Replacing '" << Args[i] <<
"' with '" << Repl <<
"'\n";
138 Args[i] = GetStableCStr(SavedStrings, Repl);
141 }
else if (Edit[0] ==
'x' || Edit[0] ==
'X') {
142 auto Option = Edit.substr(1);
143 for (
unsigned i = 1; i < Args.size();) {
144 if (Option == Args[i]) {
145 OS <<
"### Deleting argument " << Args[i] <<
'\n';
146 Args.erase(Args.begin() + i);
147 if (Edit[0] ==
'X') {
148 if (i < Args.size()) {
149 OS <<
"### Deleting argument " << Args[i] <<
'\n';
150 Args.erase(Args.begin() + i);
152 OS <<
"### Invalid X edit, end of command line!\n";
157 }
else if (Edit[0] ==
'O') {
158 for (
unsigned i = 1; i < Args.size();) {
159 const char *A = Args[i];
163 if (A[0] ==
'-' && A[1] ==
'O' &&
164 (A[2] ==
'\0' || (A[3] ==
'\0' && (A[2] ==
's' || A[2] ==
'z' || (
'0' <= A[2] && A[2] <=
'9'))))) {
165 OS <<
"### Deleting argument " << Args[i] <<
'\n';
166 Args.erase(Args.begin() + i);
170 OS <<
"### Adding argument " << Edit <<
" at end\n";
171 Args.push_back(GetStableCStr(SavedStrings,
'-' + Edit.str()));
173 OS <<
"### Unrecognized edit: " << Edit <<
"\n";
180 ApplyQAOverride(SmallVectorImpl<const char *> &Args,
const char *OverrideStr, std::set<std::string> &SavedStrings) {
181 raw_ostream *OS = &llvm::errs();
183 if (OverrideStr[0] ==
'#') {
188 *OS <<
"### CCC_OVERRIDE_OPTIONS: " << OverrideStr <<
"\n";
192 const char *S = OverrideStr;
194 const char *End = ::strchr(S,
' ');
198 ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
205 extern int cc1_main(ArrayRef<const char *> Argv,
const char *Argv0,
void *MainAddr);
206 extern int cc1as_main(ArrayRef<const char *> Argv,
const char *Argv0,
void *MainAddr);
207 extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
const char *Argv0,
void *MainAddr);
209 static void insertTargetAndModeArgs(
const ParsedClangName &NameParts,
210 SmallVectorImpl<const char *> &ArgVector,
211 std::set<std::string> &SavedStrings) {
215 int InsertionPoint = 0;
216 if (ArgVector.size() > 0)
219 if (NameParts.DriverMode) {
221 ArgVector.insert(ArgVector.begin() + InsertionPoint, GetStableCStr(SavedStrings, NameParts.DriverMode));
224 if (NameParts.TargetIsValid) {
225 const char *arr[] = {
"-target", GetStableCStr(SavedStrings, NameParts.TargetPrefix)};
226 ArgVector.insert(ArgVector.begin() + InsertionPoint, std::begin(arr), std::end(arr));
230 static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver, SmallVectorImpl<const char *> &Opts) {
231 llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
233 for (
const char *Opt : Opts)
234 if (
char *NumberSignPtr =
const_cast<char *
>(::strchr(Opt,
'#')))
235 *NumberSignPtr =
'=';
238 template <
class T>
static T checkEnvVar(
const char *EnvOptSet,
const char *EnvOptFile, std::string &OptFile) {
239 const char *Str = ::getenv(EnvOptSet);
244 if (
const char *Var = ::getenv(EnvOptFile))
249 static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
250 TheDriver.CCPrintOptions =
251 checkEnvVar<bool>(
"CC_PRINT_OPTIONS",
"CC_PRINT_OPTIONS_FILE", TheDriver.CCPrintOptionsFilename);
252 if (checkEnvVar<bool>(
"CC_PRINT_HEADERS",
"CC_PRINT_HEADERS_FILE", TheDriver.CCPrintHeadersFilename)) {
253 TheDriver.CCPrintHeadersFormat = HIFMT_Textual;
254 TheDriver.CCPrintHeadersFiltering = HIFIL_None;
257 checkEnvVar<std::string>(
"CC_PRINT_HEADERS_FORMAT",
"CC_PRINT_HEADERS_FILE", TheDriver.CCPrintHeadersFilename);
258 if (!EnvVar.empty()) {
259 TheDriver.CCPrintHeadersFormat = stringToHeaderIncludeFormatKind(EnvVar.c_str());
260 if (!TheDriver.CCPrintHeadersFormat) {
261 TheDriver.Diag(clang::diag::err_drv_print_header_env_var) << 0 << EnvVar;
265 const char *FilteringStr = ::getenv(
"CC_PRINT_HEADERS_FILTERING");
266 HeaderIncludeFilteringKind Filtering;
267 if (!stringToHeaderIncludeFiltering(FilteringStr, Filtering)) {
268 TheDriver.Diag(clang::diag::err_drv_print_header_env_var) << 1 << FilteringStr;
272 if ((TheDriver.CCPrintHeadersFormat == HIFMT_Textual && Filtering != HIFIL_None) ||
273 (TheDriver.CCPrintHeadersFormat == HIFMT_JSON && Filtering != HIFIL_Only_Direct_System)) {
274 TheDriver.Diag(clang::diag::err_drv_print_header_env_var_combination) << EnvVar << FilteringStr;
277 TheDriver.CCPrintHeadersFiltering = Filtering;
281 TheDriver.CCLogDiagnostics =
282 checkEnvVar<bool>(
"CC_LOG_DIAGNOSTICS",
"CC_LOG_DIAGNOSTICS_FILE", TheDriver.CCLogDiagnosticsFilename);
283 TheDriver.CCPrintProcessStats =
284 checkEnvVar<bool>(
"CC_PRINT_PROC_STAT",
"CC_PRINT_PROC_STAT_FILE", TheDriver.CCPrintStatReportFilename);
289 static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
const std::string &Path) {
292 StringRef ExeBasename(llvm::sys::path::stem(Path));
293 if (ExeBasename.equals_insensitive(
"cl"))
294 ExeBasename =
"clang-cl";
295 DiagClient->setPrefix(std::string(ExeBasename));
298 static void SetInstallDir(SmallVectorImpl<const char *> &argv, Driver &TheDriver,
bool CanonicalPrefixes) {
302 SmallString<128> InstalledPath(argv[0]);
305 if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
306 if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(llvm::sys::path::filename(InstalledPath.str())))
307 InstalledPath = *Tmp;
310 if (CanonicalPrefixes)
311 llvm::sys::fs::make_absolute(InstalledPath);
313 StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
314 if (llvm::sys::fs::exists(InstalledPathParent))
315 TheDriver.setInstalledDir(InstalledPathParent);
318 static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV) {
323 llvm::cl::ResetAllOptionOccurrences();
325 llvm::BumpPtrAllocator A;
326 llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine);
327 if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) {
328 llvm::errs() << toString(std::move(Err)) <<
'\n';
331 StringRef Tool = ArgV[1];
332 void *GetExecutablePathVP = (
void *)(intptr_t)GetExecutablePath;
334 return cc1_main(ArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP);
335 if (Tool ==
"-cc1as")
336 return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
337 if (Tool ==
"-cc1gen-reproducer")
338 return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
340 llvm::errs() <<
"error: unknown integrated tool '" << Tool <<
"'. "
341 <<
"Valid tools include '-cc1' and '-cc1as'.\n";
345 int clang_main(
int Argc,
char **Argv) {
347 llvm::InitLLVM X(Argc, Argv);
348 llvm::setBugReportMsg(
"PLEASE submit a bug report to " BUG_REPORT_URL
349 " and include the crash backtrace, preprocessed "
350 "source, and associated run script.\n");
351 SmallVector<const char *, 256> Args(Argv, Argv + Argc);
353 if (llvm::sys::Process::FixupStandardFileDescriptors())
356 llvm::InitializeAllTargets();
358 llvm::BumpPtrAllocator A;
359 llvm::StringSaver Saver(A);
368 bool ClangCLMode = IsClangCL(getDriverMode(Args[0], llvm::ArrayRef(Args).slice(1)));
369 enum { Default, POSIX, Windows } RSPQuoting = Default;
370 for (
const char *F : Args) {
371 if (strcmp(F,
"--rsp-quoting=posix") == 0)
373 else if (strcmp(F,
"--rsp-quoting=windows") == 0)
374 RSPQuoting = Windows;
380 bool MarkEOLs = ClangCLMode;
382 llvm::cl::TokenizerCallback Tokenizer;
383 if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
384 Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
386 Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
388 if (MarkEOLs && Args.size() > 1 && StringRef(Args[1]).startswith(
"-cc1"))
390 llvm::cl::ExpansionContext ECtx(A, Tokenizer);
391 ECtx.setMarkEOLs(MarkEOLs);
392 if (llvm::Error Err = ECtx.expandResponseFiles(Args)) {
393 llvm::errs() << toString(std::move(Err)) <<
'\n';
399 auto FirstArg = llvm::find_if(llvm::drop_begin(Args), [](
const char *A) {
return A !=
nullptr; });
400 if (FirstArg != Args.end() && StringRef(*FirstArg).startswith(
"-cc1")) {
403 auto newEnd = std::remove(Args.begin(), Args.end(),
nullptr);
404 Args.resize(newEnd - Args.begin());
406 return ExecuteCC1Tool(Args);
411 bool CanonicalPrefixes =
true;
412 for (
int i = 1, size = Args.size(); i < size; ++i) {
414 if (Args[i] ==
nullptr)
416 if (StringRef(Args[i]) ==
"-canonical-prefixes")
417 CanonicalPrefixes =
true;
418 else if (StringRef(Args[i]) ==
"-no-canonical-prefixes")
419 CanonicalPrefixes =
false;
426 std::optional<std::string> OptCL = llvm::sys::Process::GetEnv(
"CL");
428 SmallVector<const char *, 8> PrependedOpts;
429 getCLEnvVarOptions(*OptCL, Saver, PrependedOpts);
432 Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
435 std::optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv(
"_CL_");
437 SmallVector<const char *, 8> AppendedOpts;
438 getCLEnvVarOptions(*Opt_CL_, Saver, AppendedOpts);
441 Args.append(AppendedOpts.begin(), AppendedOpts.end());
445 std::set<std::string> SavedStrings;
448 if (
const char *OverrideStr = ::getenv(
"CCC_OVERRIDE_OPTIONS")) {
450 ApplyQAOverride(Args, OverrideStr, SavedStrings);
459 std::string Path = GetExecutablePath(Args[0],
false);
465 bool UseNewCC1Process = CLANG_SPAWN_CC1;
466 for (
const char *Arg : Args)
467 UseNewCC1Process = llvm::StringSwitch<bool>(Arg)
468 .Case(
"-fno-integrated-cc1",
true)
469 .Case(
"-fintegrated-cc1",
false)
470 .Default(UseNewCC1Process);
472 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(Args);
474 TextDiagnosticPrinter *DiagClient =
new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
475 FixupDiagPrefixExeName(DiagClient, Path);
477 IntrusiveRefCntPtr<DiagnosticIDs> DiagID(
new DiagnosticIDs());
479 DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
481 if (!DiagOpts->DiagnosticSerializationFile.empty()) {
482 auto SerializedConsumer =
483 clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile, &*DiagOpts,
true);
484 Diags.setClient(
new ChainedDiagnosticConsumer(Diags.takeClient(), std::move(SerializedConsumer)));
487 ProcessWarningOptions(Diags, *DiagOpts,
false);
489 Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
490 SetInstallDir(Args, TheDriver, CanonicalPrefixes);
491 auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(Args[0]);
492 TheDriver.setTargetAndMode(TargetAndMode);
494 insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings);
496 if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver))
499 if (!UseNewCC1Process) {
500 TheDriver.CC1Main = &ExecuteCC1Tool;
502 llvm::CrashRecoveryContext::Enable();
505 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args));
507 Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash;
508 if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) {
509 auto Level = llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue())
510 .Case(
"off", Driver::ReproLevel::Off)
511 .Case(
"crash", Driver::ReproLevel::OnCrash)
512 .Case(
"error", Driver::ReproLevel::OnError)
513 .Case(
"always", Driver::ReproLevel::Always)
514 .Default(std::nullopt);
516 llvm::errs() <<
"Unknown value for " << A->getSpelling() <<
": '" << A->getValue() <<
"'\n";
521 if (!!::getenv(
"FORCE_CLANG_DIAGNOSTICS_CRASH"))
522 ReproLevel = Driver::ReproLevel::Always;
525 bool IsCrash =
false;
526 Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok;
528 const Command *FailingCommand =
nullptr;
529 if (!C->getJobs().empty())
530 FailingCommand = &*C->getJobs().begin();
531 if (C && !C->containsError()) {
532 SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
533 Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
535 for (
const auto &P : FailingCommands) {
536 int CommandRes = P.first;
537 FailingCommand = P.second;
545 IsCrash = CommandRes < 0 || CommandRes == 70;
547 IsCrash |= CommandRes == 3;
554 IsCrash |= CommandRes > 128;
556 CommandStatus = IsCrash ? Driver::CommandStatus::Crash : Driver::CommandStatus::Error;
564 if (::getenv(
"FORCE_CLANG_DIAGNOSTICS_CRASH"))
565 llvm::dbgs() << llvm::getBugReportMsg();
566 if (FailingCommand !=
nullptr &&
567 TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel, *C, *FailingCommand))
570 Diags.getClient()->finish();
572 if (!UseNewCC1Process && IsCrash) {
575 llvm::BuryPointer(llvm::TimerGroup::aquireDefaultGroup());
579 llvm::TimerGroup::printAll(llvm::errs());
580 llvm::TimerGroup::clearAll();