/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/driver/driver.cpp
Line | Count | Source (jump to first uncovered line) |
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/Options.h" |
22 | | #include "clang/Driver/ToolChain.h" |
23 | | #include "clang/Frontend/ChainedDiagnosticConsumer.h" |
24 | | #include "clang/Frontend/CompilerInvocation.h" |
25 | | #include "clang/Frontend/SerializedDiagnosticPrinter.h" |
26 | | #include "clang/Frontend/TextDiagnosticPrinter.h" |
27 | | #include "clang/Frontend/Utils.h" |
28 | | #include "llvm/ADT/ArrayRef.h" |
29 | | #include "llvm/ADT/SmallString.h" |
30 | | #include "llvm/ADT/SmallVector.h" |
31 | | #include "llvm/Option/ArgList.h" |
32 | | #include "llvm/Option/OptTable.h" |
33 | | #include "llvm/Option/Option.h" |
34 | | #include "llvm/Support/BuryPointer.h" |
35 | | #include "llvm/Support/CommandLine.h" |
36 | | #include "llvm/Support/CrashRecoveryContext.h" |
37 | | #include "llvm/Support/ErrorHandling.h" |
38 | | #include "llvm/Support/FileSystem.h" |
39 | | #include "llvm/Support/InitLLVM.h" |
40 | | #include "llvm/Support/LLVMDriver.h" |
41 | | #include "llvm/Support/Path.h" |
42 | | #include "llvm/Support/PrettyStackTrace.h" |
43 | | #include "llvm/Support/Process.h" |
44 | | #include "llvm/Support/Program.h" |
45 | | #include "llvm/Support/Regex.h" |
46 | | #include "llvm/Support/Signals.h" |
47 | | #include "llvm/Support/StringSaver.h" |
48 | | #include "llvm/Support/TargetSelect.h" |
49 | | #include "llvm/Support/Timer.h" |
50 | | #include "llvm/Support/raw_ostream.h" |
51 | | #include "llvm/TargetParser/Host.h" |
52 | | #include <memory> |
53 | | #include <optional> |
54 | | #include <set> |
55 | | #include <system_error> |
56 | | using namespace clang; |
57 | | using namespace clang::driver; |
58 | | using namespace llvm::opt; |
59 | | |
60 | 20.7k | std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) { |
61 | 20.7k | if (!CanonicalPrefixes) { |
62 | 82 | SmallString<128> ExecutablePath(Argv0); |
63 | | // Do a PATH lookup if Argv0 isn't a valid path. |
64 | 82 | if (!llvm::sys::fs::exists(ExecutablePath)) |
65 | 0 | if (llvm::ErrorOr<std::string> P = |
66 | 0 | llvm::sys::findProgramByName(ExecutablePath)) |
67 | 0 | ExecutablePath = *P; |
68 | 82 | return std::string(ExecutablePath.str()); |
69 | 82 | } |
70 | | |
71 | | // This just needs to be some symbol in the binary; C++ doesn't |
72 | | // allow taking the address of ::main however. |
73 | 20.6k | void *P = (void*) (intptr_t) GetExecutablePath; |
74 | 20.6k | return llvm::sys::fs::getMainExecutable(Argv0, P); |
75 | 20.7k | } |
76 | | |
77 | | static const char *GetStableCStr(std::set<std::string> &SavedStrings, |
78 | 102 | StringRef S) { |
79 | 102 | return SavedStrings.insert(std::string(S)).first->c_str(); |
80 | 102 | } |
81 | | |
82 | | /// ApplyOneQAOverride - Apply a list of edits to the input argument lists. |
83 | | /// |
84 | | /// The input string is a space separated list of edits to perform, |
85 | | /// they are applied in order to the input argument lists. Edits |
86 | | /// should be one of the following forms: |
87 | | /// |
88 | | /// '#': Silence information about the changes to the command line arguments. |
89 | | /// |
90 | | /// '^': Add FOO as a new argument at the beginning of the command line. |
91 | | /// |
92 | | /// '+': Add FOO as a new argument at the end of the command line. |
93 | | /// |
94 | | /// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command |
95 | | /// line. |
96 | | /// |
97 | | /// 'xOPTION': Removes all instances of the literal argument OPTION. |
98 | | /// |
99 | | /// 'XOPTION': Removes all instances of the literal argument OPTION, |
100 | | /// and the following argument. |
101 | | /// |
102 | | /// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox' |
103 | | /// at the end of the command line. |
104 | | /// |
105 | | /// \param OS - The stream to write edit information to. |
106 | | /// \param Args - The vector of command line arguments. |
107 | | /// \param Edit - The override command to perform. |
108 | | /// \param SavedStrings - Set to use for storing string representations. |
109 | | static void ApplyOneQAOverride(raw_ostream &OS, |
110 | | SmallVectorImpl<const char*> &Args, |
111 | | StringRef Edit, |
112 | 16 | std::set<std::string> &SavedStrings) { |
113 | | // This does not need to be efficient. |
114 | | |
115 | 16 | if (Edit[0] == '^') { |
116 | 1 | const char *Str = |
117 | 1 | GetStableCStr(SavedStrings, Edit.substr(1)); |
118 | 1 | OS << "### Adding argument " << Str << " at beginning\n"; |
119 | 1 | Args.insert(Args.begin() + 1, Str); |
120 | 15 | } else if (Edit[0] == '+') { |
121 | 11 | const char *Str = |
122 | 11 | GetStableCStr(SavedStrings, Edit.substr(1)); |
123 | 11 | OS << "### Adding argument " << Str << " at end\n"; |
124 | 11 | Args.push_back(Str); |
125 | 11 | } else if (4 Edit[0] == 's'4 && Edit[1] == '/'0 && Edit.endswith("/")0 && |
126 | 4 | Edit.slice(2, Edit.size() - 1).contains('/')0 ) { |
127 | 0 | StringRef MatchPattern = Edit.substr(2).split('/').first; |
128 | 0 | StringRef ReplPattern = Edit.substr(2).split('/').second; |
129 | 0 | ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1); |
130 | |
|
131 | 0 | for (unsigned i = 1, e = Args.size(); i != e; ++i) { |
132 | | // Ignore end-of-line response file markers |
133 | 0 | if (Args[i] == nullptr) |
134 | 0 | continue; |
135 | 0 | std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]); |
136 | |
|
137 | 0 | if (Repl != Args[i]) { |
138 | 0 | OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n"; |
139 | 0 | Args[i] = GetStableCStr(SavedStrings, Repl); |
140 | 0 | } |
141 | 0 | } |
142 | 4 | } else if (Edit[0] == 'x' || Edit[0] == 'X'2 ) { |
143 | 3 | auto Option = Edit.substr(1); |
144 | 34 | for (unsigned i = 1; i < Args.size();) { |
145 | 31 | if (Option == Args[i]) { |
146 | 4 | OS << "### Deleting argument " << Args[i] << '\n'; |
147 | 4 | Args.erase(Args.begin() + i); |
148 | 4 | if (Edit[0] == 'X') { |
149 | 1 | if (i < Args.size()) { |
150 | 1 | OS << "### Deleting argument " << Args[i] << '\n'; |
151 | 1 | Args.erase(Args.begin() + i); |
152 | 1 | } else |
153 | 0 | OS << "### Invalid X edit, end of command line!\n"; |
154 | 1 | } |
155 | 4 | } else |
156 | 27 | ++i; |
157 | 31 | } |
158 | 3 | } else if (1 Edit[0] == 'O'1 ) { |
159 | 11 | for (unsigned i = 1; i < Args.size();) { |
160 | 10 | const char *A = Args[i]; |
161 | | // Ignore end-of-line response file markers |
162 | 10 | if (A == nullptr) |
163 | 0 | continue; |
164 | 10 | if (A[0] == '-' && A[1] == 'O'8 && |
165 | 10 | (7 A[2] == '\0'7 || |
166 | 7 | (6 A[3] == '\0'6 && (5 A[2] == 's'5 || A[2] == 'z'4 || |
167 | 6 | (3 '0' <= A[2]3 && A[2] <= '9'3 ))))) { |
168 | 6 | OS << "### Deleting argument " << Args[i] << '\n'; |
169 | 6 | Args.erase(Args.begin() + i); |
170 | 6 | } else |
171 | 4 | ++i; |
172 | 10 | } |
173 | 1 | OS << "### Adding argument " << Edit << " at end\n"; |
174 | 1 | Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str())); |
175 | 1 | } else { |
176 | 0 | OS << "### Unrecognized edit: " << Edit << "\n"; |
177 | 0 | } |
178 | 16 | } |
179 | | |
180 | | /// ApplyQAOverride - Apply a space separated list of edits to the |
181 | | /// input argument lists. See ApplyOneQAOverride. |
182 | | static void ApplyQAOverride(SmallVectorImpl<const char*> &Args, |
183 | | const char *OverrideStr, |
184 | 4 | std::set<std::string> &SavedStrings) { |
185 | 4 | raw_ostream *OS = &llvm::errs(); |
186 | | |
187 | 4 | if (OverrideStr[0] == '#') { |
188 | 1 | ++OverrideStr; |
189 | 1 | OS = &llvm::nulls(); |
190 | 1 | } |
191 | | |
192 | 4 | *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n"; |
193 | | |
194 | | // This does not need to be efficient. |
195 | | |
196 | 4 | const char *S = OverrideStr; |
197 | 21 | while (*S) { |
198 | 17 | const char *End = ::strchr(S, ' '); |
199 | 17 | if (!End) |
200 | 3 | End = S + strlen(S); |
201 | 17 | if (End != S) |
202 | 16 | ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings); |
203 | 17 | S = End; |
204 | 17 | if (*S != '\0') |
205 | 14 | ++S; |
206 | 17 | } |
207 | 4 | } |
208 | | |
209 | | extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, |
210 | | void *MainAddr); |
211 | | extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, |
212 | | void *MainAddr); |
213 | | extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv, |
214 | | const char *Argv0, void *MainAddr, |
215 | | const llvm::ToolContext &); |
216 | | |
217 | | static void insertTargetAndModeArgs(const ParsedClangName &NameParts, |
218 | | SmallVectorImpl<const char *> &ArgVector, |
219 | 20.7k | std::set<std::string> &SavedStrings) { |
220 | | // Put target and mode arguments at the start of argument list so that |
221 | | // arguments specified in command line could override them. Avoid putting |
222 | | // them at index 0, as an option like '-cc1' must remain the first. |
223 | 20.7k | int InsertionPoint = 0; |
224 | 20.7k | if (ArgVector.size() > 0) |
225 | 20.7k | ++InsertionPoint; |
226 | | |
227 | 20.7k | if (NameParts.DriverMode) { |
228 | | // Add the mode flag to the arguments. |
229 | 59 | ArgVector.insert(ArgVector.begin() + InsertionPoint, |
230 | 59 | GetStableCStr(SavedStrings, NameParts.DriverMode)); |
231 | 59 | } |
232 | | |
233 | 20.7k | if (NameParts.TargetIsValid) { |
234 | 30 | const char *arr[] = {"-target", GetStableCStr(SavedStrings, |
235 | 30 | NameParts.TargetPrefix)}; |
236 | 30 | ArgVector.insert(ArgVector.begin() + InsertionPoint, |
237 | 30 | std::begin(arr), std::end(arr)); |
238 | 30 | } |
239 | 20.7k | } |
240 | | |
241 | | static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver, |
242 | 3 | SmallVectorImpl<const char *> &Opts) { |
243 | 3 | llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts); |
244 | | // The first instance of '#' should be replaced with '=' in each option. |
245 | 3 | for (const char *Opt : Opts) |
246 | 5 | if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#'))) |
247 | 0 | *NumberSignPtr = '='; |
248 | 3 | } |
249 | | |
250 | | template <class T> |
251 | | static T checkEnvVar(const char *EnvOptSet, const char *EnvOptFile, |
252 | 124k | std::string &OptFile) { |
253 | 124k | const char *Str = ::getenv(EnvOptSet); |
254 | 124k | if (!Str) |
255 | 124k | return T{}; |
256 | | |
257 | 28 | T OptVal = Str; |
258 | 28 | if (const char *Var = ::getenv(EnvOptFile)) |
259 | 9 | OptFile = Var; |
260 | 28 | return OptVal; |
261 | 124k | } driver.cpp:bool checkEnvVar<bool>(char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Line | Count | Source | 252 | 103k | std::string &OptFile) { | 253 | 103k | const char *Str = ::getenv(EnvOptSet); | 254 | 103k | if (!Str) | 255 | 103k | return T{}; | 256 | | | 257 | 25 | T OptVal = Str; | 258 | 25 | if (const char *Var = ::getenv(EnvOptFile)) | 259 | 6 | OptFile = Var; | 260 | 25 | return OptVal; | 261 | 103k | } |
driver.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > checkEnvVar<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(char const*, char const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Line | Count | Source | 252 | 20.7k | std::string &OptFile) { | 253 | 20.7k | const char *Str = ::getenv(EnvOptSet); | 254 | 20.7k | if (!Str) | 255 | 20.7k | return T{}; | 256 | | | 257 | 3 | T OptVal = Str; | 258 | 3 | if (const char *Var = ::getenv(EnvOptFile)) | 259 | 3 | OptFile = Var; | 260 | 3 | return OptVal; | 261 | 20.7k | } |
|
262 | | |
263 | 20.7k | static bool SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) { |
264 | 20.7k | TheDriver.CCPrintOptions = |
265 | 20.7k | checkEnvVar<bool>("CC_PRINT_OPTIONS", "CC_PRINT_OPTIONS_FILE", |
266 | 20.7k | TheDriver.CCPrintOptionsFilename); |
267 | 20.7k | if (checkEnvVar<bool>("CC_PRINT_HEADERS", "CC_PRINT_HEADERS_FILE", |
268 | 20.7k | TheDriver.CCPrintHeadersFilename)) { |
269 | 9 | TheDriver.CCPrintHeadersFormat = HIFMT_Textual; |
270 | 9 | TheDriver.CCPrintHeadersFiltering = HIFIL_None; |
271 | 20.7k | } else { |
272 | 20.7k | std::string EnvVar = checkEnvVar<std::string>( |
273 | 20.7k | "CC_PRINT_HEADERS_FORMAT", "CC_PRINT_HEADERS_FILE", |
274 | 20.7k | TheDriver.CCPrintHeadersFilename); |
275 | 20.7k | if (!EnvVar.empty()) { |
276 | 3 | TheDriver.CCPrintHeadersFormat = |
277 | 3 | stringToHeaderIncludeFormatKind(EnvVar.c_str()); |
278 | 3 | if (!TheDriver.CCPrintHeadersFormat) { |
279 | 0 | TheDriver.Diag(clang::diag::err_drv_print_header_env_var) |
280 | 0 | << 0 << EnvVar; |
281 | 0 | return false; |
282 | 0 | } |
283 | | |
284 | 3 | const char *FilteringStr = ::getenv("CC_PRINT_HEADERS_FILTERING"); |
285 | 3 | HeaderIncludeFilteringKind Filtering; |
286 | 3 | if (!stringToHeaderIncludeFiltering(FilteringStr, Filtering)) { |
287 | 0 | TheDriver.Diag(clang::diag::err_drv_print_header_env_var) |
288 | 0 | << 1 << FilteringStr; |
289 | 0 | return false; |
290 | 0 | } |
291 | | |
292 | 3 | if ((TheDriver.CCPrintHeadersFormat == HIFMT_Textual && |
293 | 3 | Filtering != HIFIL_None1 ) || |
294 | 3 | (2 TheDriver.CCPrintHeadersFormat == HIFMT_JSON2 && |
295 | 2 | Filtering != HIFIL_Only_Direct_System)) { |
296 | 2 | TheDriver.Diag(clang::diag::err_drv_print_header_env_var_combination) |
297 | 2 | << EnvVar << FilteringStr; |
298 | 2 | return false; |
299 | 2 | } |
300 | 1 | TheDriver.CCPrintHeadersFiltering = Filtering; |
301 | 1 | } |
302 | 20.7k | } |
303 | | |
304 | 20.7k | TheDriver.CCLogDiagnostics = |
305 | 20.7k | checkEnvVar<bool>("CC_LOG_DIAGNOSTICS", "CC_LOG_DIAGNOSTICS_FILE", |
306 | 20.7k | TheDriver.CCLogDiagnosticsFilename); |
307 | 20.7k | TheDriver.CCPrintProcessStats = |
308 | 20.7k | checkEnvVar<bool>("CC_PRINT_PROC_STAT", "CC_PRINT_PROC_STAT_FILE", |
309 | 20.7k | TheDriver.CCPrintStatReportFilename); |
310 | 20.7k | TheDriver.CCPrintInternalStats = |
311 | 20.7k | checkEnvVar<bool>("CC_PRINT_INTERNAL_STAT", "CC_PRINT_INTERNAL_STAT_FILE", |
312 | 20.7k | TheDriver.CCPrintInternalStatReportFilename); |
313 | | |
314 | 20.7k | return true; |
315 | 20.7k | } |
316 | | |
317 | | static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient, |
318 | 20.7k | const std::string &Path) { |
319 | | // If the clang binary happens to be named cl.exe for compatibility reasons, |
320 | | // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC. |
321 | 20.7k | StringRef ExeBasename(llvm::sys::path::stem(Path)); |
322 | 20.7k | if (ExeBasename.equals_insensitive("cl")) |
323 | 2 | ExeBasename = "clang-cl"; |
324 | 20.7k | DiagClient->setPrefix(std::string(ExeBasename)); |
325 | 20.7k | } |
326 | | |
327 | | static void SetInstallDir(SmallVectorImpl<const char *> &argv, |
328 | 20.7k | Driver &TheDriver, bool CanonicalPrefixes) { |
329 | | // Attempt to find the original path used to invoke the driver, to determine |
330 | | // the installed path. We do this manually, because we want to support that |
331 | | // path being a symlink. |
332 | 20.7k | SmallString<128> InstalledPath(argv[0]); |
333 | | |
334 | | // Do a PATH lookup, if there are no directory components. |
335 | 20.7k | if (llvm::sys::path::filename(InstalledPath) == InstalledPath) |
336 | 3 | if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName( |
337 | 3 | llvm::sys::path::filename(InstalledPath.str()))) |
338 | 3 | InstalledPath = *Tmp; |
339 | | |
340 | | // FIXME: We don't actually canonicalize this, we just make it absolute. |
341 | 20.7k | if (CanonicalPrefixes) |
342 | 20.6k | llvm::sys::fs::make_absolute(InstalledPath); |
343 | | |
344 | 20.7k | StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath)); |
345 | 20.7k | if (llvm::sys::fs::exists(InstalledPathParent)) |
346 | 20.7k | TheDriver.setInstalledDir(InstalledPathParent); |
347 | 20.7k | } |
348 | | |
349 | | static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV, |
350 | 46.2k | const llvm::ToolContext &ToolContext) { |
351 | | // If we call the cc1 tool from the clangDriver library (through |
352 | | // Driver::CC1Main), we need to clean up the options usage count. The options |
353 | | // are currently global, and they might have been used previously by the |
354 | | // driver. |
355 | 46.2k | llvm::cl::ResetAllOptionOccurrences(); |
356 | | |
357 | 46.2k | llvm::BumpPtrAllocator A; |
358 | 46.2k | llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine); |
359 | 46.2k | if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) { |
360 | 0 | llvm::errs() << toString(std::move(Err)) << '\n'; |
361 | 0 | return 1; |
362 | 0 | } |
363 | 46.2k | StringRef Tool = ArgV[1]; |
364 | 46.2k | void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath; |
365 | 46.2k | if (Tool == "-cc1") |
366 | 46.2k | return cc1_main(ArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP); |
367 | 66 | if (Tool == "-cc1as") |
368 | 62 | return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP); |
369 | 4 | if (Tool == "-cc1gen-reproducer") |
370 | 3 | return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0], |
371 | 3 | GetExecutablePathVP, ToolContext); |
372 | | // Reject unknown tools. |
373 | 1 | llvm::errs() << "error: unknown integrated tool '" << Tool << "'. " |
374 | 1 | << "Valid tools include '-cc1' and '-cc1as'.\n"; |
375 | 1 | return 1; |
376 | 4 | } |
377 | | |
378 | 61.1k | int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) { |
379 | 61.1k | noteBottomOfStack(); |
380 | 61.1k | llvm::InitLLVM X(Argc, Argv); |
381 | 61.1k | llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL |
382 | 61.1k | " and include the crash backtrace, preprocessed " |
383 | 61.1k | "source, and associated run script.\n"); |
384 | 61.1k | SmallVector<const char *, 256> Args(Argv, Argv + Argc); |
385 | | |
386 | 61.1k | if (llvm::sys::Process::FixupStandardFileDescriptors()) |
387 | 0 | return 1; |
388 | | |
389 | 61.1k | llvm::InitializeAllTargets(); |
390 | | |
391 | 61.1k | llvm::BumpPtrAllocator A; |
392 | 61.1k | llvm::StringSaver Saver(A); |
393 | | |
394 | 61.1k | const char *ProgName = |
395 | 61.1k | ToolContext.NeedsPrependArg ? ToolContext.PrependArg0 : ToolContext.Path; |
396 | | |
397 | 61.1k | bool ClangCLMode = |
398 | 61.1k | IsClangCL(getDriverMode(ProgName, llvm::ArrayRef(Args).slice(1))); |
399 | | |
400 | 61.1k | if (llvm::Error Err = expandResponseFiles(Args, ClangCLMode, A)) { |
401 | 1 | llvm::errs() << toString(std::move(Err)) << '\n'; |
402 | 1 | return 1; |
403 | 1 | } |
404 | | |
405 | | // Handle -cc1 integrated tools. |
406 | 61.1k | if (Args.size() >= 2 && StringRef(Args[1]).startswith("-cc1")) |
407 | 40.4k | return ExecuteCC1Tool(Args, ToolContext); |
408 | | |
409 | | // Handle options that need handling before the real command line parsing in |
410 | | // Driver::BuildCompilation() |
411 | 20.7k | bool CanonicalPrefixes = true; |
412 | 539k | for (int i = 1, size = Args.size(); i < size; ++i518k ) { |
413 | | // Skip end-of-line response file markers |
414 | 518k | if (Args[i] == nullptr) |
415 | 2 | continue; |
416 | 518k | if (StringRef(Args[i]) == "-canonical-prefixes") |
417 | 2 | CanonicalPrefixes = true; |
418 | 518k | else if (StringRef(Args[i]) == "-no-canonical-prefixes") |
419 | 84 | CanonicalPrefixes = false; |
420 | 518k | } |
421 | | |
422 | | // Handle CL and _CL_ which permits additional command line options to be |
423 | | // prepended or appended. |
424 | 20.7k | if (ClangCLMode) { |
425 | | // Arguments in "CL" are prepended. |
426 | 643 | std::optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL"); |
427 | 643 | if (OptCL) { |
428 | 2 | SmallVector<const char *, 8> PrependedOpts; |
429 | 2 | getCLEnvVarOptions(*OptCL, Saver, PrependedOpts); |
430 | | |
431 | | // Insert right after the program name to prepend to the argument list. |
432 | 2 | Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end()); |
433 | 2 | } |
434 | | // Arguments in "_CL_" are appended. |
435 | 643 | std::optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_"); |
436 | 643 | if (Opt_CL_) { |
437 | 1 | SmallVector<const char *, 8> AppendedOpts; |
438 | 1 | getCLEnvVarOptions(*Opt_CL_, Saver, AppendedOpts); |
439 | | |
440 | | // Insert at the end of the argument list to append. |
441 | 1 | Args.append(AppendedOpts.begin(), AppendedOpts.end()); |
442 | 1 | } |
443 | 643 | } |
444 | | |
445 | 20.7k | std::set<std::string> SavedStrings; |
446 | | // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the |
447 | | // scenes. |
448 | 20.7k | if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) { |
449 | | // FIXME: Driver shouldn't take extra initial argument. |
450 | 4 | ApplyQAOverride(Args, OverrideStr, SavedStrings); |
451 | 4 | } |
452 | | |
453 | 20.7k | std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes); |
454 | | |
455 | | // Whether the cc1 tool should be called inside the current process, or if we |
456 | | // should spawn a new clang subprocess (old behavior). |
457 | | // Not having an additional process saves some execution time of Windows, |
458 | | // and makes debugging and profiling easier. |
459 | 20.7k | bool UseNewCC1Process = CLANG_SPAWN_CC1; |
460 | 20.7k | for (const char *Arg : Args) |
461 | 539k | UseNewCC1Process = llvm::StringSwitch<bool>(Arg) |
462 | 539k | .Case("-fno-integrated-cc1", true) |
463 | 539k | .Case("-fintegrated-cc1", false) |
464 | 539k | .Default(UseNewCC1Process); |
465 | | |
466 | 20.7k | IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = |
467 | 20.7k | CreateAndPopulateDiagOpts(Args); |
468 | | |
469 | 20.7k | TextDiagnosticPrinter *DiagClient |
470 | 20.7k | = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); |
471 | 20.7k | FixupDiagPrefixExeName(DiagClient, ProgName); |
472 | | |
473 | 20.7k | IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); |
474 | | |
475 | 20.7k | DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); |
476 | | |
477 | 20.7k | if (!DiagOpts->DiagnosticSerializationFile.empty()) { |
478 | 12 | auto SerializedConsumer = |
479 | 12 | clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile, |
480 | 12 | &*DiagOpts, /*MergeChildRecords=*/true); |
481 | 12 | Diags.setClient(new ChainedDiagnosticConsumer( |
482 | 12 | Diags.takeClient(), std::move(SerializedConsumer))); |
483 | 12 | } |
484 | | |
485 | 20.7k | ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); |
486 | | |
487 | 20.7k | Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); |
488 | 20.7k | SetInstallDir(Args, TheDriver, CanonicalPrefixes); |
489 | 20.7k | auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(ProgName); |
490 | 20.7k | TheDriver.setTargetAndMode(TargetAndMode); |
491 | | // If -canonical-prefixes is set, GetExecutablePath will have resolved Path |
492 | | // to the llvm driver binary, not clang. In this case, we need to use |
493 | | // PrependArg which should be clang-*. Checking just CanonicalPrefixes is |
494 | | // safe even in the normal case because PrependArg will be null so |
495 | | // setPrependArg will be a no-op. |
496 | 20.7k | if (ToolContext.NeedsPrependArg || CanonicalPrefixes) |
497 | 20.6k | TheDriver.setPrependArg(ToolContext.PrependArg); |
498 | | |
499 | 20.7k | insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings); |
500 | | |
501 | 20.7k | if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver)) |
502 | 2 | return 1; |
503 | | |
504 | 20.7k | if (!UseNewCC1Process) { |
505 | 20.7k | TheDriver.CC1Main = [ToolContext](SmallVectorImpl<const char *> &ArgV) { |
506 | 5.86k | return ExecuteCC1Tool(ArgV, ToolContext); |
507 | 5.86k | }; |
508 | | // Ensure the CC1Command actually catches cc1 crashes |
509 | 20.7k | llvm::CrashRecoveryContext::Enable(); |
510 | 20.7k | } |
511 | | |
512 | 20.7k | std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); |
513 | | |
514 | 20.7k | Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash; |
515 | 20.7k | if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) { |
516 | 21 | auto Level = |
517 | 21 | llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue()) |
518 | 21 | .Case("off", Driver::ReproLevel::Off) |
519 | 21 | .Case("crash", Driver::ReproLevel::OnCrash) |
520 | 21 | .Case("error", Driver::ReproLevel::OnError) |
521 | 21 | .Case("always", Driver::ReproLevel::Always) |
522 | 21 | .Default(std::nullopt); |
523 | 21 | if (!Level) { |
524 | 1 | llvm::errs() << "Unknown value for " << A->getSpelling() << ": '" |
525 | 1 | << A->getValue() << "'\n"; |
526 | 1 | return 1; |
527 | 1 | } |
528 | 20 | ReproLevel = *Level; |
529 | 20 | } |
530 | 20.7k | if (!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) |
531 | 14 | ReproLevel = Driver::ReproLevel::Always; |
532 | | |
533 | 20.7k | int Res = 1; |
534 | 20.7k | bool IsCrash = false; |
535 | 20.7k | Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok; |
536 | | // Pretend the first command failed if ReproStatus is Always. |
537 | 20.7k | const Command *FailingCommand = nullptr; |
538 | 20.7k | if (!C->getJobs().empty()) |
539 | 18.8k | FailingCommand = &*C->getJobs().begin(); |
540 | 20.7k | if (C && !C->containsError()) { |
541 | 20.6k | SmallVector<std::pair<int, const Command *>, 4> FailingCommands; |
542 | 20.6k | Res = TheDriver.ExecuteCompilation(*C, FailingCommands); |
543 | | |
544 | 20.6k | for (const auto &P : FailingCommands) { |
545 | 313 | int CommandRes = P.first; |
546 | 313 | FailingCommand = P.second; |
547 | 313 | if (!Res) |
548 | 302 | Res = CommandRes; |
549 | | |
550 | | // If result status is < 0, then the driver command signalled an error. |
551 | | // If result status is 70, then the driver command reported a fatal error. |
552 | | // On Windows, abort will return an exit code of 3. In these cases, |
553 | | // generate additional diagnostic information if possible. |
554 | 313 | IsCrash = CommandRes < 0 || CommandRes == 70; |
555 | | #ifdef _WIN32 |
556 | | IsCrash |= CommandRes == 3; |
557 | | #endif |
558 | 313 | #if LLVM_ON_UNIX |
559 | | // When running in integrated-cc1 mode, the CrashRecoveryContext returns |
560 | | // the same codes as if the program crashed. See section "Exit Status for |
561 | | // Commands": |
562 | | // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html |
563 | 313 | IsCrash |= CommandRes > 128; |
564 | 313 | #endif |
565 | 313 | CommandStatus = |
566 | 313 | IsCrash ? Driver::CommandStatus::Crash24 : Driver::CommandStatus::Error289 ; |
567 | 313 | if (IsCrash) |
568 | 24 | break; |
569 | 313 | } |
570 | 20.6k | } |
571 | | |
572 | | // Print the bug report message that would be printed if we did actually |
573 | | // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH. |
574 | 20.7k | if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) |
575 | 14 | llvm::dbgs() << llvm::getBugReportMsg(); |
576 | 20.7k | if (FailingCommand != nullptr && |
577 | 20.7k | TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel, |
578 | 18.8k | *C, *FailingCommand)) |
579 | 42 | Res = 1; |
580 | | |
581 | 20.7k | Diags.getClient()->finish(); |
582 | | |
583 | 20.7k | if (!UseNewCC1Process && IsCrash20.7k ) { |
584 | | // When crashing in -fintegrated-cc1 mode, bury the timer pointers, because |
585 | | // the internal linked list might point to already released stack frames. |
586 | 24 | llvm::BuryPointer(llvm::TimerGroup::aquireDefaultGroup()); |
587 | 20.7k | } else { |
588 | | // If any timers were active but haven't been destroyed yet, print their |
589 | | // results now. This happens in -disable-free mode. |
590 | 20.7k | llvm::TimerGroup::printAll(llvm::errs()); |
591 | 20.7k | llvm::TimerGroup::clearAll(); |
592 | 20.7k | } |
593 | | |
594 | | #ifdef _WIN32 |
595 | | // Exit status should not be negative on Win32, unless abnormal termination. |
596 | | // Once abnormal termination was caught, negative status should not be |
597 | | // propagated. |
598 | | if (Res < 0) |
599 | | Res = 1; |
600 | | #endif |
601 | | |
602 | | // If we have multiple failing commands, we return the result of the first |
603 | | // failing command. |
604 | 20.7k | return Res; |
605 | 20.7k | } |