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