1//===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This is the entry point to the clang driver; it is a thin wrapper
10// for functionality in the Driver clang library.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Driver/Driver.h"
15#include "clang/Basic/DiagnosticOptions.h"
16#include "clang/Basic/HeaderInclude.h"
17#include "clang/Basic/Stack.h"
18#include "clang/Config/config.h"
19#include "clang/Driver/Compilation.h"
20#include "clang/Driver/DriverDiagnostic.h"
21#include "clang/Driver/ToolChain.h"
22#include "clang/Frontend/ChainedDiagnosticConsumer.h"
23#include "clang/Frontend/CompilerInvocation.h"
24#include "clang/Frontend/SerializedDiagnosticPrinter.h"
25#include "clang/Frontend/TextDiagnosticPrinter.h"
26#include "clang/Frontend/Utils.h"
27#include "clang/Options/Options.h"
28#include "llvm/ADT/ArrayRef.h"
29#include "llvm/ADT/SmallString.h"
30#include "llvm/ADT/SmallVector.h"
31#include "llvm/ADT/StringSet.h"
32#include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
33#include "llvm/Option/ArgList.h"
34#include "llvm/Option/OptTable.h"
35#include "llvm/Option/Option.h"
36#include "llvm/Support/BuryPointer.h"
37#include "llvm/Support/CommandLine.h"
38#include "llvm/Support/CrashRecoveryContext.h"
39#include "llvm/Support/ErrorHandling.h"
40#include "llvm/Support/FileSystem.h"
41#include "llvm/Support/IOSandbox.h"
42#include "llvm/Support/LLVMDriver.h"
43#include "llvm/Support/Path.h"
44#include "llvm/Support/PrettyStackTrace.h"
45#include "llvm/Support/Process.h"
46#include "llvm/Support/Program.h"
47#include "llvm/Support/Signals.h"
48#include "llvm/Support/StringSaver.h"
49#include "llvm/Support/TargetSelect.h"
50#include "llvm/Support/Timer.h"
51#include "llvm/Support/VirtualFileSystem.h"
52#include "llvm/Support/raw_ostream.h"
53#include "llvm/TargetParser/Host.h"
54#include <memory>
55#include <optional>
56#include <set>
57#include <system_error>
58
59using namespace clang;
60using namespace clang::driver;
61using namespace llvm::opt;
62
63std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
64 if (!CanonicalPrefixes) {
65 SmallString<128> ExecutablePath(Argv0);
66 // Do a PATH lookup if Argv0 isn't a valid path.
67 if (!llvm::sys::fs::exists(Path: ExecutablePath))
68 if (llvm::ErrorOr<std::string> P =
69 llvm::sys::findProgramByName(Name: ExecutablePath))
70 ExecutablePath = *P;
71 return std::string(ExecutablePath);
72 }
73
74 // This just needs to be some symbol in the binary; C++ doesn't
75 // allow taking the address of ::main however.
76 void *P = (void*) (intptr_t) GetExecutablePath;
77 return llvm::sys::fs::getMainExecutable(argv0: Argv0, MainExecAddr: P);
78}
79
80static const char *GetStableCStr(llvm::StringSet<> &SavedStrings, StringRef S) {
81 return SavedStrings.insert(key: S).first->getKeyData();
82}
83
84extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
85 void *MainAddr);
86extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
87 void *MainAddr);
88extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
89 const char *Argv0, void *MainAddr,
90 const llvm::ToolContext &);
91
92static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
93 SmallVectorImpl<const char *> &ArgVector,
94 llvm::StringSet<> &SavedStrings) {
95 // Put target and mode arguments at the start of argument list so that
96 // arguments specified in command line could override them. Avoid putting
97 // them at index 0, as an option like '-cc1' must remain the first.
98 int InsertionPoint = 0;
99 if (ArgVector.size() > 0)
100 ++InsertionPoint;
101
102 if (NameParts.DriverMode) {
103 // Add the mode flag to the arguments.
104 ArgVector.insert(I: ArgVector.begin() + InsertionPoint,
105 Elt: GetStableCStr(SavedStrings, S: NameParts.DriverMode));
106 }
107
108 if (NameParts.TargetIsValid) {
109 const char *arr[] = {"-target", GetStableCStr(SavedStrings,
110 S: NameParts.TargetPrefix)};
111 ArgVector.insert(I: ArgVector.begin() + InsertionPoint,
112 From: std::begin(arr&: arr), To: std::end(arr&: arr));
113 }
114}
115
116static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
117 SmallVectorImpl<const char *> &Opts) {
118 llvm::cl::TokenizeWindowsCommandLine(Source: EnvValue, Saver, NewArgv&: Opts);
119 // The first instance of '#' should be replaced with '=' in each option.
120 for (const char *Opt : Opts)
121 if (char *NumberSignPtr = const_cast<char *>(::strchr(s: Opt, c: '#')))
122 *NumberSignPtr = '=';
123}
124
125template <class T>
126static T checkEnvVar(const char *EnvOptSet, const char *EnvOptFile,
127 std::string &OptFile) {
128 const char *Str = ::getenv(name: EnvOptSet);
129 if (!Str)
130 return T{};
131
132 T OptVal = Str;
133 if (const char *Var = ::getenv(name: EnvOptFile))
134 OptFile = Var;
135 return OptVal;
136}
137
138static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
139 TheDriver.CCPrintOptions =
140 checkEnvVar<bool>(EnvOptSet: "CC_PRINT_OPTIONS", EnvOptFile: "CC_PRINT_OPTIONS_FILE",
141 OptFile&: TheDriver.CCPrintOptionsFilename);
142 if (checkEnvVar<bool>(EnvOptSet: "CC_PRINT_HEADERS", EnvOptFile: "CC_PRINT_HEADERS_FILE",
143 OptFile&: TheDriver.CCPrintHeadersFilename)) {
144 TheDriver.CCPrintHeadersFormat = HIFMT_Textual;
145 TheDriver.CCPrintHeadersFiltering = HIFIL_None;
146 } else {
147 std::string EnvVar = checkEnvVar<std::string>(
148 EnvOptSet: "CC_PRINT_HEADERS_FORMAT", EnvOptFile: "CC_PRINT_HEADERS_FILE",
149 OptFile&: TheDriver.CCPrintHeadersFilename);
150 if (!EnvVar.empty()) {
151 TheDriver.CCPrintHeadersFormat =
152 stringToHeaderIncludeFormatKind(Str: EnvVar.c_str());
153 if (!TheDriver.CCPrintHeadersFormat) {
154 TheDriver.Diag(DiagID: clang::diag::err_drv_print_header_env_var)
155 << 0 << EnvVar;
156 return false;
157 }
158
159 const char *FilteringStr = ::getenv(name: "CC_PRINT_HEADERS_FILTERING");
160 if (!FilteringStr) {
161 TheDriver.Diag(DiagID: clang::diag::err_drv_print_header_env_var_invalid_format)
162 << EnvVar;
163 return false;
164 }
165 HeaderIncludeFilteringKind Filtering;
166 if (!stringToHeaderIncludeFiltering(Str: FilteringStr, Kind&: Filtering)) {
167 TheDriver.Diag(DiagID: clang::diag::err_drv_print_header_env_var)
168 << 1 << FilteringStr;
169 return false;
170 }
171
172 if ((TheDriver.CCPrintHeadersFormat == HIFMT_Textual &&
173 Filtering != HIFIL_None) ||
174 (TheDriver.CCPrintHeadersFormat == HIFMT_JSON &&
175 Filtering == HIFIL_None)) {
176 TheDriver.Diag(DiagID: clang::diag::err_drv_print_header_env_var_combination)
177 << EnvVar << FilteringStr;
178 return false;
179 }
180 TheDriver.CCPrintHeadersFiltering = Filtering;
181 }
182 }
183
184 TheDriver.CCLogDiagnostics =
185 checkEnvVar<bool>(EnvOptSet: "CC_LOG_DIAGNOSTICS", EnvOptFile: "CC_LOG_DIAGNOSTICS_FILE",
186 OptFile&: TheDriver.CCLogDiagnosticsFilename);
187 TheDriver.CCPrintProcessStats =
188 checkEnvVar<bool>(EnvOptSet: "CC_PRINT_PROC_STAT", EnvOptFile: "CC_PRINT_PROC_STAT_FILE",
189 OptFile&: TheDriver.CCPrintStatReportFilename);
190 TheDriver.CCPrintInternalStats =
191 checkEnvVar<bool>(EnvOptSet: "CC_PRINT_INTERNAL_STAT", EnvOptFile: "CC_PRINT_INTERNAL_STAT_FILE",
192 OptFile&: TheDriver.CCPrintInternalStatReportFilename);
193
194 return true;
195}
196
197static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
198 const std::string &Path) {
199 // If the clang binary happens to be named cl.exe for compatibility reasons,
200 // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
201 StringRef ExeBasename(llvm::sys::path::stem(path: Path));
202 if (ExeBasename.equals_insensitive(RHS: "cl"))
203 ExeBasename = "clang-cl";
204 DiagClient->setPrefix(std::string(ExeBasename));
205}
206
207static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
208 const llvm::ToolContext &ToolContext,
209 IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
210 // If we call the cc1 tool from the clangDriver library (through
211 // Driver::CC1Main), we need to clean up the options usage count. The options
212 // are currently global, and they might have been used previously by the
213 // driver.
214 llvm::cl::ResetAllOptionOccurrences();
215
216 llvm::BumpPtrAllocator A;
217 llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine,
218 VFS.get());
219 if (llvm::Error Err = ECtx.expandResponseFiles(Argv&: ArgV)) {
220 llvm::errs() << toString(E: std::move(Err)) << '\n';
221 return 1;
222 }
223 StringRef Tool = ArgV[1];
224 void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
225 if (Tool == "-cc1")
226 return cc1_main(Argv: ArrayRef(ArgV).slice(N: 1), Argv0: ArgV[0], MainAddr: GetExecutablePathVP);
227 if (Tool == "-cc1as")
228 return cc1as_main(Argv: ArrayRef(ArgV).slice(N: 2), Argv0: ArgV[0], MainAddr: GetExecutablePathVP);
229 if (Tool == "-cc1gen-reproducer")
230 return cc1gen_reproducer_main(Argv: ArrayRef(ArgV).slice(N: 2), Argv0: ArgV[0],
231 MainAddr: GetExecutablePathVP, ToolContext);
232 // Reject unknown tools.
233 llvm::errs()
234 << "error: unknown integrated tool '" << Tool << "'. "
235 << "Valid tools include '-cc1', '-cc1as' and '-cc1gen-reproducer'.\n";
236 return 1;
237}
238
239int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
240 noteBottomOfStack();
241 llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL
242 " and include the crash backtrace, preprocessed "
243 "source, and associated run script.\n");
244 SmallVector<const char *, 256> Args(Argv, Argv + Argc);
245
246 if (llvm::sys::Process::FixupStandardFileDescriptors())
247 return 1;
248
249 llvm::InitializeAllTargets();
250
251 llvm::BumpPtrAllocator A;
252 llvm::StringSaver Saver(A);
253
254 const char *ProgName =
255 ToolContext.NeedsPrependArg ? ToolContext.PrependArg : ToolContext.Path;
256
257 bool ClangCLMode =
258 IsClangCL(DriverMode: getDriverMode(ProgName, Args: llvm::ArrayRef(Args).slice(N: 1)));
259
260 auto VFS = llvm::vfs::getRealFileSystem();
261
262 if (llvm::Error Err = expandResponseFiles(Args, ClangCLMode, Alloc&: A, FS: VFS.get())) {
263 llvm::errs() << toString(E: std::move(Err)) << '\n';
264 return 1;
265 }
266
267 // Handle -cc1 integrated tools.
268 if (Args.size() >= 2 && StringRef(Args[1]).starts_with(Prefix: "-cc1")) {
269 // Note that this only enables the sandbox for direct -cc1 invocations and
270 // out-of-process -cc1 invocations launched by the driver. For in-process
271 // -cc1 invocations launched by the driver, the sandbox is enabled in
272 // CC1Command::Execute() for better crash recovery.
273 auto EnableSandbox = llvm::sys::sandbox::scopedEnable();
274 return ExecuteCC1Tool(ArgV&: Args, ToolContext, VFS);
275 }
276
277 // Handle options that need handling before the real command line parsing in
278 // Driver::BuildCompilation()
279 bool CanonicalPrefixes = true;
280 for (int i = 1, size = Args.size(); i < size; ++i) {
281 // Skip end-of-line response file markers
282 if (Args[i] == nullptr)
283 continue;
284 if (StringRef(Args[i]) == "-canonical-prefixes")
285 CanonicalPrefixes = true;
286 else if (StringRef(Args[i]) == "-no-canonical-prefixes")
287 CanonicalPrefixes = false;
288 }
289
290 // Handle CL and _CL_ which permits additional command line options to be
291 // prepended or appended.
292 if (ClangCLMode) {
293 // Arguments in "CL" are prepended.
294 std::optional<std::string> OptCL = llvm::sys::Process::GetEnv(name: "CL");
295 if (OptCL) {
296 SmallVector<const char *, 8> PrependedOpts;
297 getCLEnvVarOptions(EnvValue&: *OptCL, Saver, Opts&: PrependedOpts);
298
299 // Insert right after the program name to prepend to the argument list.
300 Args.insert(I: Args.begin() + 1, From: PrependedOpts.begin(), To: PrependedOpts.end());
301 }
302 // Arguments in "_CL_" are appended.
303 std::optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv(name: "_CL_");
304 if (Opt_CL_) {
305 SmallVector<const char *, 8> AppendedOpts;
306 getCLEnvVarOptions(EnvValue&: *Opt_CL_, Saver, Opts&: AppendedOpts);
307
308 // Insert at the end of the argument list to append.
309 Args.append(in_start: AppendedOpts.begin(), in_end: AppendedOpts.end());
310 }
311 }
312
313 llvm::StringSet<> SavedStrings;
314 // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
315 // scenes.
316 if (const char *OverrideStr = ::getenv(name: "CCC_OVERRIDE_OPTIONS")) {
317 // FIXME: Driver shouldn't take extra initial argument.
318 driver::applyOverrideOptions(Args, OverrideOpts: OverrideStr, SavedStrings,
319 EnvVar: "CCC_OVERRIDE_OPTIONS", OS: &llvm::errs());
320 }
321
322 std::string Path = GetExecutablePath(Argv0: ToolContext.Path, CanonicalPrefixes);
323
324 // Whether the cc1 tool should be called inside the current process, or if we
325 // should spawn a new clang subprocess (old behavior).
326 // Not having an additional process saves some execution time of Windows,
327 // and makes debugging and profiling easier.
328 bool UseNewCC1Process = CLANG_SPAWN_CC1;
329 for (const char *Arg : Args)
330 UseNewCC1Process = llvm::StringSwitch<bool>(Arg)
331 .Case(S: "-fno-integrated-cc1", Value: true)
332 .Case(S: "-fintegrated-cc1", Value: false)
333 .Default(Value: UseNewCC1Process);
334
335 std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(Argv: Args);
336 // Driver's diagnostics don't use suppression mappings, so don't bother
337 // parsing them. CC1 still receives full args, so this doesn't impact other
338 // actions.
339 DiagOpts->DiagnosticSuppressionMappingsFile.clear();
340
341 TextDiagnosticPrinter *DiagClient =
342 new TextDiagnosticPrinter(llvm::errs(), *DiagOpts);
343 FixupDiagPrefixExeName(DiagClient, Path: ProgName);
344
345 DiagnosticsEngine Diags(DiagnosticIDs::create(), *DiagOpts, DiagClient);
346
347 if (!DiagOpts->DiagnosticSerializationFile.empty()) {
348 auto SerializedConsumer =
349 clang::serialized_diags::create(OutputFile: DiagOpts->DiagnosticSerializationFile,
350 DiagOpts&: *DiagOpts, /*MergeChildRecords=*/true);
351 Diags.setClient(client: new ChainedDiagnosticConsumer(
352 Diags.takeClient(), std::move(SerializedConsumer)));
353 }
354
355 ProcessWarningOptions(Diags, Opts: *DiagOpts, VFS&: *VFS, /*ReportDiags=*/false);
356
357 Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags,
358 /*Title=*/"clang LLVM compiler", VFS);
359 auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(ProgName);
360 TheDriver.setTargetAndMode(TargetAndMode);
361 // If -canonical-prefixes is set, GetExecutablePath will have resolved Path
362 // to the llvm driver binary, not clang. In this case, we need to use
363 // PrependArg which should be clang-*. Checking just CanonicalPrefixes is
364 // safe even in the normal case because PrependArg will be null so
365 // setPrependArg will be a no-op.
366 if (ToolContext.NeedsPrependArg || CanonicalPrefixes)
367 TheDriver.setPrependArg(ToolContext.PrependArg);
368
369 insertTargetAndModeArgs(NameParts: TargetAndMode, ArgVector&: Args, SavedStrings);
370
371 if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver))
372 return 1;
373
374 auto ExecuteCC1WithContext = [&ToolContext,
375 &VFS](SmallVectorImpl<const char *> &ArgV) {
376 return ExecuteCC1Tool(ArgV, ToolContext, VFS);
377 };
378 if (!UseNewCC1Process) {
379 TheDriver.CC1Main = ExecuteCC1WithContext;
380 // Ensure the CC1Command actually catches cc1 crashes
381 llvm::CrashRecoveryContext::Enable();
382 }
383
384 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args));
385
386 Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash;
387 if (Arg *A = C->getArgs().getLastArg(Ids: options::OPT_gen_reproducer_eq)) {
388 auto Level =
389 llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue())
390 .Case(S: "off", Value: Driver::ReproLevel::Off)
391 .Case(S: "crash", Value: Driver::ReproLevel::OnCrash)
392 .Case(S: "error", Value: Driver::ReproLevel::OnError)
393 .Case(S: "always", Value: Driver::ReproLevel::Always)
394 .Default(Value: std::nullopt);
395 if (!Level) {
396 llvm::errs() << "Unknown value for " << A->getSpelling() << ": '"
397 << A->getValue() << "'\n";
398 return 1;
399 }
400 ReproLevel = *Level;
401 }
402 if (!!::getenv(name: "FORCE_CLANG_DIAGNOSTICS_CRASH"))
403 ReproLevel = Driver::ReproLevel::Always;
404
405 int Res = 1;
406 bool IsCrash = false;
407 Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok;
408 // Pretend the first command failed if ReproStatus is Always.
409 const Command *FailingCommand = nullptr;
410 if (!C->getJobs().empty())
411 FailingCommand = &*C->getJobs().begin();
412 if (C && !C->containsError()) {
413 SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
414 Res = TheDriver.ExecuteCompilation(C&: *C, FailingCommands);
415
416 for (const auto &P : FailingCommands) {
417 int CommandRes = P.first;
418 FailingCommand = P.second;
419 if (!Res)
420 Res = CommandRes;
421
422 // If result status is < 0, then the driver command signalled an error.
423 // If result status is 70, then the driver command reported a fatal error.
424 // On Windows, abort will return an exit code of 3. In these cases,
425 // generate additional diagnostic information if possible.
426 IsCrash = CommandRes < 0 || CommandRes == 70;
427#ifdef _WIN32
428 IsCrash |= CommandRes == 3;
429#endif
430#if LLVM_ON_UNIX
431 // When running in integrated-cc1 mode, the CrashRecoveryContext returns
432 // the same codes as if the program crashed. See section "Exit Status for
433 // Commands":
434 // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html
435 IsCrash |= CommandRes > 128;
436#endif
437 CommandStatus =
438 IsCrash ? Driver::CommandStatus::Crash : Driver::CommandStatus::Error;
439 if (IsCrash)
440 break;
441 }
442 }
443
444 // Print the bug report message that would be printed if we did actually
445 // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH.
446 if (::getenv(name: "FORCE_CLANG_DIAGNOSTICS_CRASH"))
447 llvm::dbgs() << llvm::getBugReportMsg();
448 if (FailingCommand != nullptr &&
449 TheDriver.maybeGenerateCompilationDiagnostics(CS: CommandStatus, Level: ReproLevel,
450 C&: *C, FailingCommand: *FailingCommand))
451 Res = 1;
452
453 Diags.getClient()->finish();
454
455 if (!UseNewCC1Process && IsCrash) {
456 // When crashing in -fintegrated-cc1 mode, bury the timer pointers, because
457 // the internal linked list might point to already released stack frames.
458 llvm::BuryPointer(Ptr: llvm::TimerGroup::acquireTimerGlobals());
459 } else {
460 // If any timers were active but haven't been destroyed yet, print their
461 // results now. This happens in -disable-free mode.
462 llvm::TimerGroup::printAll(OS&: llvm::errs());
463 llvm::TimerGroup::clearAll();
464 }
465
466#ifdef _WIN32
467 // Exit status should not be negative on Win32, unless abnormal termination.
468 // Once abnormal termination was caught, negative status should not be
469 // propagated.
470 if (Res < 0)
471 Res = 1;
472#endif
473
474 // If we have multiple failing commands, we return the result of the first
475 // failing command.
476 return Res;
477}
478