Branch data Line data Source code
1 : : //===-- driver.cpp - Clang GCC-Compatible Driver --------------------------===//
2 : : //
3 : : // The LLVM Compiler Infrastructure
4 : : //
5 : : // This file is distributed under the University of Illinois Open Source
6 : : // License. See LICENSE.TXT for details.
7 : : //
8 : : //===----------------------------------------------------------------------===//
9 : : //
10 : : // This is the entry point to the clang driver; it is a thin wrapper
11 : : // for functionality in the Driver clang library.
12 : : //
13 : : //===----------------------------------------------------------------------===//
14 : :
15 : : #include "clang/Driver/Driver.h"
16 : : #include "clang/Basic/DiagnosticOptions.h"
17 : : #include "clang/Driver/Compilation.h"
18 : : #include "clang/Driver/DriverDiagnostic.h"
19 : : #include "clang/Driver/Options.h"
20 : : #include "clang/Driver/ToolChain.h"
21 : : #include "clang/Frontend/ChainedDiagnosticConsumer.h"
22 : : #include "clang/Frontend/CompilerInvocation.h"
23 : : #include "clang/Frontend/SerializedDiagnosticPrinter.h"
24 : : #include "clang/Frontend/TextDiagnosticPrinter.h"
25 : : #include "clang/Frontend/Utils.h"
26 : : #include "llvm/ADT/ArrayRef.h"
27 : : #include "llvm/ADT/SmallString.h"
28 : : #include "llvm/ADT/SmallVector.h"
29 : : #include "llvm/Option/ArgList.h"
30 : : #include "llvm/Option/OptTable.h"
31 : : #include "llvm/Option/Option.h"
32 : : #include "llvm/Support/CommandLine.h"
33 : : #include "llvm/Support/ErrorHandling.h"
34 : : #include "llvm/Support/FileSystem.h"
35 : : #include "llvm/Support/Host.h"
36 : : #include "llvm/Support/InitLLVM.h"
37 : : #include "llvm/Support/Path.h"
38 : : #include "llvm/Support/Process.h"
39 : : #include "llvm/Support/Program.h"
40 : : #include "llvm/Support/Regex.h"
41 : : #include "llvm/Support/Signals.h"
42 : : #include "llvm/Support/StringSaver.h"
43 : : #include "llvm/Support/TargetSelect.h"
44 : : #include "llvm/Support/Timer.h"
45 : : #include "llvm/Support/raw_ostream.h"
46 : : #include <memory>
47 : : #include <set>
48 : : #include <system_error>
49 : : using namespace clang;
50 : : using namespace clang::driver;
51 : : using namespace llvm::opt;
52 : :
53 : 35 : std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
54 [ - + ]: 35 : if (!CanonicalPrefixes) {
55 : 0 : SmallString<128> ExecutablePath(Argv0);
56 : : // Do a PATH lookup if Argv0 isn't a valid path.
57 [ # # ]: 0 : if (!llvm::sys::fs::exists(ExecutablePath))
58 [ # # ]: 0 : if (llvm::ErrorOr<std::string> P =
59 : 0 : llvm::sys::findProgramByName(ExecutablePath))
60 : 0 : ExecutablePath = *P;
61 : 0 : return ExecutablePath.str();
62 : : }
63 : :
64 : : // This just needs to be some symbol in the binary; C++ doesn't
65 : : // allow taking the address of ::main however.
66 : 35 : void *P = (void*) (intptr_t) GetExecutablePath;
67 : 35 : return llvm::sys::fs::getMainExecutable(Argv0, P);
68 : : }
69 : :
70 : 0 : static const char *GetStableCStr(std::set<std::string> &SavedStrings,
71 : : StringRef S) {
72 : 0 : return SavedStrings.insert(S).first->c_str();
73 : : }
74 : :
75 : : /// ApplyQAOverride - Apply a list of edits to the input argument lists.
76 : : ///
77 : : /// The input string is a space separate list of edits to perform,
78 : : /// they are applied in order to the input argument lists. Edits
79 : : /// should be one of the following forms:
80 : : ///
81 : : /// '#': Silence information about the changes to the command line arguments.
82 : : ///
83 : : /// '^': Add FOO as a new argument at the beginning of the command line.
84 : : ///
85 : : /// '+': Add FOO as a new argument at the end of the command line.
86 : : ///
87 : : /// 's/XXX/YYY/': Substitute the regular expression XXX with YYY in the command
88 : : /// line.
89 : : ///
90 : : /// 'xOPTION': Removes all instances of the literal argument OPTION.
91 : : ///
92 : : /// 'XOPTION': Removes all instances of the literal argument OPTION,
93 : : /// and the following argument.
94 : : ///
95 : : /// 'Ox': Removes all flags matching 'O' or 'O[sz0-9]' and adds 'Ox'
96 : : /// at the end of the command line.
97 : : ///
98 : : /// \param OS - The stream to write edit information to.
99 : : /// \param Args - The vector of command line arguments.
100 : : /// \param Edit - The override command to perform.
101 : : /// \param SavedStrings - Set to use for storing string representations.
102 : 0 : static void ApplyOneQAOverride(raw_ostream &OS,
103 : : SmallVectorImpl<const char*> &Args,
104 : : StringRef Edit,
105 : : std::set<std::string> &SavedStrings) {
106 : : // This does not need to be efficient.
107 : :
108 [ # # ]: 0 : if (Edit[0] == '^') {
109 : : const char *Str =
110 : 0 : GetStableCStr(SavedStrings, Edit.substr(1));
111 : 0 : OS << "### Adding argument " << Str << " at beginning\n";
112 : 0 : Args.insert(Args.begin() + 1, Str);
113 [ # # ]: 0 : } else if (Edit[0] == '+') {
114 : : const char *Str =
115 : 0 : GetStableCStr(SavedStrings, Edit.substr(1));
116 : 0 : OS << "### Adding argument " << Str << " at end\n";
117 : 0 : Args.push_back(Str);
118 [ # # ][ # # ]: 0 : } else if (Edit[0] == 's' && Edit[1] == '/' && Edit.endswith("/") &&
[ # # ][ # # ]
[ # # ]
119 : 0 : Edit.slice(2, Edit.size()-1).find('/') != StringRef::npos) {
120 : 0 : StringRef MatchPattern = Edit.substr(2).split('/').first;
121 : 0 : StringRef ReplPattern = Edit.substr(2).split('/').second;
122 : 0 : ReplPattern = ReplPattern.slice(0, ReplPattern.size()-1);
123 : :
124 [ # # ]: 0 : for (unsigned i = 1, e = Args.size(); i != e; ++i) {
125 : : // Ignore end-of-line response file markers
126 [ # # ]: 0 : if (Args[i] == nullptr)
127 : 0 : continue;
128 : 0 : std::string Repl = llvm::Regex(MatchPattern).sub(ReplPattern, Args[i]);
129 : :
130 [ # # ]: 0 : if (Repl != Args[i]) {
131 : 0 : OS << "### Replacing '" << Args[i] << "' with '" << Repl << "'\n";
132 : 0 : Args[i] = GetStableCStr(SavedStrings, Repl);
133 : : }
134 : : }
135 [ # # ][ # # ]: 0 : } else if (Edit[0] == 'x' || Edit[0] == 'X') {
[ # # ]
136 : 0 : auto Option = Edit.substr(1);
137 [ # # ]: 0 : for (unsigned i = 1; i < Args.size();) {
138 [ # # ]: 0 : if (Option == Args[i]) {
139 : 0 : OS << "### Deleting argument " << Args[i] << '\n';
140 : 0 : Args.erase(Args.begin() + i);
141 [ # # ]: 0 : if (Edit[0] == 'X') {
142 [ # # ]: 0 : if (i < Args.size()) {
143 : 0 : OS << "### Deleting argument " << Args[i] << '\n';
144 : 0 : Args.erase(Args.begin() + i);
145 : : } else
146 : 0 : OS << "### Invalid X edit, end of command line!\n";
147 : : }
148 : : } else
149 : 0 : ++i;
150 : : }
151 [ # # ]: 0 : } else if (Edit[0] == 'O') {
152 [ # # ]: 0 : for (unsigned i = 1; i < Args.size();) {
153 : 0 : const char *A = Args[i];
154 : : // Ignore end-of-line response file markers
155 [ # # ]: 0 : if (A == nullptr)
156 : 0 : continue;
157 [ # # ][ # # ]: 0 : if (A[0] == '-' && A[1] == 'O' &&
[ # # ]
158 [ # # ]: 0 : (A[2] == '\0' ||
159 [ # # ][ # # ]: 0 : (A[3] == '\0' && (A[2] == 's' || A[2] == 'z' ||
[ # # ]
160 [ # # ]: 0 : ('0' <= A[2] && A[2] <= '9'))))) {
161 : 0 : OS << "### Deleting argument " << Args[i] << '\n';
162 : 0 : Args.erase(Args.begin() + i);
163 : : } else
164 : 0 : ++i;
165 : : }
166 : 0 : OS << "### Adding argument " << Edit << " at end\n";
167 : 0 : Args.push_back(GetStableCStr(SavedStrings, '-' + Edit.str()));
168 : : } else {
169 : 0 : OS << "### Unrecognized edit: " << Edit << "\n";
170 : : }
171 : 0 : }
172 : :
173 : : /// ApplyQAOverride - Apply a comma separate list of edits to the
174 : : /// input argument lists. See ApplyOneQAOverride.
175 : 0 : static void ApplyQAOverride(SmallVectorImpl<const char*> &Args,
176 : : const char *OverrideStr,
177 : : std::set<std::string> &SavedStrings) {
178 : 0 : raw_ostream *OS = &llvm::errs();
179 : :
180 [ # # ]: 0 : if (OverrideStr[0] == '#') {
181 : 0 : ++OverrideStr;
182 : 0 : OS = &llvm::nulls();
183 : : }
184 : :
185 : 0 : *OS << "### CCC_OVERRIDE_OPTIONS: " << OverrideStr << "\n";
186 : :
187 : : // This does not need to be efficient.
188 : :
189 : 0 : const char *S = OverrideStr;
190 [ # # ]: 0 : while (*S) {
191 : 0 : const char *End = ::strchr(S, ' ');
192 [ # # ]: 0 : if (!End)
193 : 0 : End = S + strlen(S);
194 [ # # ]: 0 : if (End != S)
195 : 0 : ApplyOneQAOverride(*OS, Args, std::string(S, End), SavedStrings);
196 : 0 : S = End;
197 [ # # ]: 0 : if (*S != '\0')
198 : 0 : ++S;
199 : : }
200 : 0 : }
201 : :
202 : : extern int cc1_main(ArrayRef<const char *> Argv, const char *Argv0,
203 : : void *MainAddr);
204 : : extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
205 : : void *MainAddr);
206 : :
207 : 35 : static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
208 : : SmallVectorImpl<const char *> &ArgVector,
209 : : std::set<std::string> &SavedStrings) {
210 : : // Put target and mode arguments at the start of argument list so that
211 : : // arguments specified in command line could override them. Avoid putting
212 : : // them at index 0, as an option like '-cc1' must remain the first.
213 : 35 : int InsertionPoint = 0;
214 [ + - ]: 35 : if (ArgVector.size() > 0)
215 : 35 : ++InsertionPoint;
216 : :
217 [ - + ]: 35 : if (NameParts.DriverMode) {
218 : : // Add the mode flag to the arguments.
219 : 0 : ArgVector.insert(ArgVector.begin() + InsertionPoint,
220 : 0 : GetStableCStr(SavedStrings, NameParts.DriverMode));
221 : : }
222 : :
223 [ - + ]: 35 : if (NameParts.TargetIsValid) {
224 : 0 : const char *arr[] = {"-target", GetStableCStr(SavedStrings,
225 : 0 : NameParts.TargetPrefix)};
226 : 0 : ArgVector.insert(ArgVector.begin() + InsertionPoint,
227 : : std::begin(arr), std::end(arr));
228 : : }
229 : 35 : }
230 : :
231 : 0 : static void getCLEnvVarOptions(std::string &EnvValue, llvm::StringSaver &Saver,
232 : : SmallVectorImpl<const char *> &Opts) {
233 : 0 : llvm::cl::TokenizeWindowsCommandLine(EnvValue, Saver, Opts);
234 : : // The first instance of '#' should be replaced with '=' in each option.
235 [ # # ]: 0 : for (const char *Opt : Opts)
236 [ # # ]: 0 : if (char *NumberSignPtr = const_cast<char *>(::strchr(Opt, '#')))
237 : 0 : *NumberSignPtr = '=';
238 : 0 : }
239 : :
240 : 35 : static void SetBackdoorDriverOutputsFromEnvVars(Driver &TheDriver) {
241 : : // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE.
242 : 35 : TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS");
243 [ - + ]: 35 : if (TheDriver.CCPrintOptions)
244 : 0 : TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE");
245 : :
246 : : // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE.
247 : 35 : TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS");
248 [ - + ]: 35 : if (TheDriver.CCPrintHeaders)
249 : 0 : TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE");
250 : :
251 : : // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE.
252 : 35 : TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS");
253 [ - + ]: 35 : if (TheDriver.CCLogDiagnostics)
254 : 0 : TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE");
255 : 35 : }
256 : :
257 : 35 : static void FixupDiagPrefixExeName(TextDiagnosticPrinter *DiagClient,
258 : : const std::string &Path) {
259 : : // If the clang binary happens to be named cl.exe for compatibility reasons,
260 : : // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC.
261 : 35 : StringRef ExeBasename(llvm::sys::path::stem(Path));
262 [ - + ]: 35 : if (ExeBasename.equals_lower("cl"))
263 : 0 : ExeBasename = "clang-cl";
264 : 35 : DiagClient->setPrefix(ExeBasename);
265 : 35 : }
266 : :
267 : : // This lets us create the DiagnosticsEngine with a properly-filled-out
268 : : // DiagnosticOptions instance.
269 : : static DiagnosticOptions *
270 : 35 : CreateAndPopulateDiagOpts(ArrayRef<const char *> argv) {
271 : 35 : auto *DiagOpts = new DiagnosticOptions;
272 : 70 : std::unique_ptr<OptTable> Opts(createDriverOptTable());
273 : : unsigned MissingArgIndex, MissingArgCount;
274 : : InputArgList Args =
275 : 70 : Opts->ParseArgs(argv.slice(1), MissingArgIndex, MissingArgCount);
276 : : // We ignore MissingArgCount and the return value of ParseDiagnosticArgs.
277 : : // Any errors that would be diagnosed here will also be diagnosed later,
278 : : // when the DiagnosticsEngine actually exists.
279 : 35 : (void)ParseDiagnosticArgs(*DiagOpts, Args);
280 : 70 : return DiagOpts;
281 : : }
282 : :
283 : 35 : static void SetInstallDir(SmallVectorImpl<const char *> &argv,
284 : : Driver &TheDriver, bool CanonicalPrefixes) {
285 : : // Attempt to find the original path used to invoke the driver, to determine
286 : : // the installed path. We do this manually, because we want to support that
287 : : // path being a symlink.
288 : 70 : SmallString<128> InstalledPath(argv[0]);
289 : :
290 : : // Do a PATH lookup, if there are no directory components.
291 [ + - ]: 70 : if (llvm::sys::path::filename(InstalledPath) == InstalledPath)
292 [ + - ]: 35 : if (llvm::ErrorOr<std::string> Tmp = llvm::sys::findProgramByName(
293 : 70 : llvm::sys::path::filename(InstalledPath.str())))
294 : 70 : InstalledPath = *Tmp;
295 : :
296 : : // FIXME: We don't actually canonicalize this, we just make it absolute.
297 [ + - ]: 35 : if (CanonicalPrefixes)
298 : 35 : llvm::sys::fs::make_absolute(InstalledPath);
299 : :
300 : 35 : StringRef InstalledPathParent(llvm::sys::path::parent_path(InstalledPath));
301 [ + - ]: 35 : if (llvm::sys::fs::exists(InstalledPathParent))
302 : 35 : TheDriver.setInstalledDir(InstalledPathParent);
303 : 35 : }
304 : :
305 : 43 : static int ExecuteCC1Tool(ArrayRef<const char *> argv, StringRef Tool) {
306 : 43 : void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath;
307 [ + + ]: 43 : if (Tool == "")
308 : 35 : return cc1_main(argv.slice(2), argv[0], GetExecutablePathVP);
309 [ + - ]: 8 : if (Tool == "as")
310 : 8 : return cc1as_main(argv.slice(2), argv[0], GetExecutablePathVP);
311 : :
312 : : // Reject unknown tools.
313 : 0 : llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
314 : 0 : << "Valid tools include '-cc1' and '-cc1as'.\n";
315 : 0 : return 1;
316 : : }
317 : :
318 : : extern "C" int ZigClang_main(int argc_, const char **argv_);
319 : 78 : int ZigClang_main(int argc_, const char **argv_) {
320 : 156 : llvm::InitLLVM X(argc_, argv_);
321 [ + + ][ + + ]: 78 : size_t argv_offset = (strcmp(argv_[1], "-cc1") == 0 || strcmp(argv_[1], "-cc1as") == 0) ? 0 : 1;
322 : 156 : SmallVector<const char *, 256> argv(argv_ + argv_offset, argv_ + argc_);
323 : :
324 [ - + ]: 78 : if (llvm::sys::Process::FixupStandardFileDescriptors())
325 : 0 : return 1;
326 : :
327 : 78 : llvm::InitializeAllTargets();
328 : 156 : auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(argv[0]);
329 : :
330 : 156 : llvm::BumpPtrAllocator A;
331 : 78 : llvm::StringSaver Saver(A);
332 : :
333 : : // Parse response files using the GNU syntax, unless we're in CL mode. There
334 : : // are two ways to put clang in CL compatibility mode: argv[0] is either
335 : : // clang-cl or cl, or --driver-mode=cl is on the command line. The normal
336 : : // command line parsing can't happen until after response file parsing, so we
337 : : // have to manually search for a --driver-mode=cl argument the hard way.
338 : : // Finally, our -cc1 tools don't care which tokenization mode we use because
339 : : // response files written by clang will tokenize the same way in either mode.
340 : 78 : bool ClangCLMode = false;
341 [ + - ][ - + ]: 156 : if (StringRef(TargetAndMode.DriverMode).equals("--driver-mode=cl") ||
[ - + ]
342 : 12488 : std::find_if(argv.begin(), argv.end(), [](const char *F) {
343 [ + - ][ - + ]: 12410 : return F && strcmp(F, "--driver-mode=cl") == 0;
344 : 12410 : }) != argv.end()) {
345 : 0 : ClangCLMode = true;
346 : : }
347 : 78 : enum { Default, POSIX, Windows } RSPQuoting = Default;
348 [ + + ]: 12488 : for (const char *F : argv) {
349 [ - + ]: 12410 : if (strcmp(F, "--rsp-quoting=posix") == 0)
350 : 0 : RSPQuoting = POSIX;
351 [ - + ]: 12410 : else if (strcmp(F, "--rsp-quoting=windows") == 0)
352 : 0 : RSPQuoting = Windows;
353 : : }
354 : :
355 : : // Determines whether we want nullptr markers in argv to indicate response
356 : : // files end-of-lines. We only use this for the /LINK driver argument with
357 : : // clang-cl.exe on Windows.
358 : 78 : bool MarkEOLs = ClangCLMode;
359 : :
360 : : llvm::cl::TokenizerCallback Tokenizer;
361 [ + - ][ + - ]: 78 : if (RSPQuoting == Windows || (RSPQuoting == Default && ClangCLMode))
[ - + ]
362 : 0 : Tokenizer = &llvm::cl::TokenizeWindowsCommandLine;
363 : : else
364 : 78 : Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
365 : :
366 [ - + ][ # # ]: 78 : if (MarkEOLs && argv.size() > 1 && StringRef(argv[1]).startswith("-cc1"))
[ # # ][ - + ]
367 : 0 : MarkEOLs = false;
368 : 78 : llvm::cl::ExpandResponseFiles(Saver, Tokenizer, argv, MarkEOLs);
369 : :
370 : : // Handle -cc1 integrated tools, even if -cc1 was expanded from a response
371 : : // file.
372 : 234 : auto FirstArg = std::find_if(argv.begin() + 1, argv.end(),
373 : 234 : [](const char *A) { return A != nullptr; });
374 [ + - ][ + + ]: 156 : if (FirstArg != argv.end() && StringRef(*FirstArg).startswith("-cc1")) {
[ + + ]
375 : : // If -cc1 came from a response file, remove the EOL sentinels.
376 [ - + ]: 43 : if (MarkEOLs) {
377 : 0 : auto newEnd = std::remove(argv.begin(), argv.end(), nullptr);
378 : 0 : argv.resize(newEnd - argv.begin());
379 : : }
380 : 43 : return ExecuteCC1Tool(argv, argv[1] + 4);
381 : : }
382 : :
383 : 35 : bool CanonicalPrefixes = true;
384 [ + + ]: 2078 : for (int i = 1, size = argv.size(); i < size; ++i) {
385 : : // Skip end-of-line response file markers
386 [ - + ]: 2043 : if (argv[i] == nullptr)
387 : 0 : continue;
388 [ - + ]: 2043 : if (StringRef(argv[i]) == "-no-canonical-prefixes") {
389 : 0 : CanonicalPrefixes = false;
390 : 0 : break;
391 : : }
392 : : }
393 : :
394 : : // Handle CL and _CL_ which permits additional command line options to be
395 : : // prepended or appended.
396 [ - + ]: 35 : if (ClangCLMode) {
397 : : // Arguments in "CL" are prepended.
398 : 0 : llvm::Optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL");
399 [ # # ]: 0 : if (OptCL.hasValue()) {
400 : 0 : SmallVector<const char *, 8> PrependedOpts;
401 : 0 : getCLEnvVarOptions(OptCL.getValue(), Saver, PrependedOpts);
402 : :
403 : : // Insert right after the program name to prepend to the argument list.
404 : 0 : argv.insert(argv.begin() + 1, PrependedOpts.begin(), PrependedOpts.end());
405 : : }
406 : : // Arguments in "_CL_" are appended.
407 : 0 : llvm::Optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_");
408 [ # # ]: 0 : if (Opt_CL_.hasValue()) {
409 : 0 : SmallVector<const char *, 8> AppendedOpts;
410 : 0 : getCLEnvVarOptions(Opt_CL_.getValue(), Saver, AppendedOpts);
411 : :
412 : : // Insert at the end of the argument list to append.
413 : 0 : argv.append(AppendedOpts.begin(), AppendedOpts.end());
414 : : }
415 : : }
416 : :
417 : 70 : std::set<std::string> SavedStrings;
418 : : // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the
419 : : // scenes.
420 [ - + ]: 35 : if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) {
421 : : // FIXME: Driver shouldn't take extra initial argument.
422 : 0 : ApplyQAOverride(argv, OverrideStr, SavedStrings);
423 : : }
424 : :
425 : 70 : std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes);
426 : :
427 : : IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
428 : 70 : CreateAndPopulateDiagOpts(argv);
429 : :
430 : : TextDiagnosticPrinter *DiagClient
431 : 35 : = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
432 : 35 : FixupDiagPrefixExeName(DiagClient, Path);
433 : :
434 : 70 : IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
435 : :
436 : 70 : DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient);
437 : :
438 [ - + ]: 35 : if (!DiagOpts->DiagnosticSerializationFile.empty()) {
439 : : auto SerializedConsumer =
440 : 0 : clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile,
441 : 0 : &*DiagOpts, /*MergeChildRecords=*/true);
442 : 0 : Diags.setClient(new ChainedDiagnosticConsumer(
443 : 0 : Diags.takeClient(), std::move(SerializedConsumer)));
444 : : }
445 : :
446 : 35 : ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
447 : :
448 : 105 : Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
449 : 35 : SetInstallDir(argv, TheDriver, CanonicalPrefixes);
450 : 35 : TheDriver.setTargetAndMode(TargetAndMode);
451 : :
452 : 35 : insertTargetAndModeArgs(TargetAndMode, argv, SavedStrings);
453 : :
454 : 35 : SetBackdoorDriverOutputsFromEnvVars(TheDriver);
455 : :
456 : 70 : std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv));
457 : 35 : int Res = 1;
458 [ + - ][ + - ]: 35 : if (C && !C->containsError()) {
[ + - ]
459 : 70 : SmallVector<std::pair<int, const Command *>, 4> FailingCommands;
460 : 35 : Res = TheDriver.ExecuteCompilation(*C, FailingCommands);
461 : :
462 : : // Force a crash to test the diagnostics.
463 [ - + ]: 35 : if (TheDriver.GenReproducer) {
464 : 0 : Diags.Report(diag::err_drv_force_crash)
465 : 0 : << !::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH");
466 : :
467 : : // Pretend that every command failed.
468 : 0 : FailingCommands.clear();
469 [ # # ]: 0 : for (const auto &J : C->getJobs())
470 [ # # ]: 0 : if (const Command *C = dyn_cast<Command>(&J))
471 : 0 : FailingCommands.push_back(std::make_pair(-1, C));
472 : : }
473 : :
474 [ - + ]: 35 : for (const auto &P : FailingCommands) {
475 : 0 : int CommandRes = P.first;
476 : 0 : const Command *FailingCommand = P.second;
477 [ # # ]: 0 : if (!Res)
478 : 0 : Res = CommandRes;
479 : :
480 : : // If result status is < 0, then the driver command signalled an error.
481 : : // If result status is 70, then the driver command reported a fatal error.
482 : : // On Windows, abort will return an exit code of 3. In these cases,
483 : : // generate additional diagnostic information if possible.
484 [ # # ][ # # ]: 0 : bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70;
485 : : #ifdef _WIN32
486 : : DiagnoseCrash |= CommandRes == 3;
487 : : #endif
488 [ # # ]: 0 : if (DiagnoseCrash) {
489 : 0 : TheDriver.generateCompilationDiagnostics(*C, *FailingCommand);
490 : 0 : break;
491 : : }
492 : : }
493 : : }
494 : :
495 : 35 : Diags.getClient()->finish();
496 : :
497 : : // If any timers were active but haven't been destroyed yet, print their
498 : : // results now. This happens in -disable-free mode.
499 : 35 : llvm::TimerGroup::printAll(llvm::errs());
500 : :
501 : : #ifdef _WIN32
502 : : // Exit status should not be negative on Win32, unless abnormal termination.
503 : : // Once abnormal termiation was caught, negative status should not be
504 : : // propagated.
505 : : if (Res < 0)
506 : : Res = 1;
507 : : #endif
508 : :
509 : : // If we have multiple failing commands, we return the result of the first
510 : : // failing command.
511 : 35 : return Res;
512 : : }
513 : :
|