╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ zig_clang_driver.cpp ─────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
279 if (StringRef(Args[i]) == "-canonical-prefixes") 280 CanonicalPrefixes = true; 281 else if (StringRef(Args[i]) == "-no-canonical-prefixes") 282 CanonicalPrefixes = false; 283 } 284 285 // Handle CL and _CL_ which permits additional command line options to be 286 // prepended or appended. 287 if (ClangCLMode) { 288 // Arguments in "CL" are prepended. 289 std::optional<std::string> OptCL = llvm::sys::Process::GetEnv("CL"); 290 if (OptCL) { 291 SmallVector<const char *, 8> PrependedOpts; 292 getCLEnvVarOptions(*OptCL, Saver, PrependedOpts); 293 294 // Insert right after the program name to prepend to the argument list. 295 Args.insert(Args.begin() + 1, PrependedOpts.begin(), PrependedOpts.end()); 296 } 297 // Arguments in "_CL_" are appended. 298 std::optional<std::string> Opt_CL_ = llvm::sys::Process::GetEnv("_CL_"); 299 if (Opt_CL_) { 300 SmallVector<const char *, 8> AppendedOpts; 301 getCLEnvVarOptions(*Opt_CL_, Saver, AppendedOpts); 302 303 // Insert at the end of the argument list to append. 304 Args.append(AppendedOpts.begin(), AppendedOpts.end()); 305 } 306 } 307 308 llvm::StringSet<> SavedStrings; 309 // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the 310 // scenes. 311 if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) { 312 // FIXME: Driver shouldn't take extra initial argument. 313 driver::applyOverrideOptions(Args, OverrideStr, SavedStrings, 314 "CCC_OVERRIDE_OPTIONS", &llvm::errs()); 315 } 316 317 std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes); 318 319 // Whether the cc1 tool should be called inside the current process, or if we 320 // should spawn a new clang subprocess (old behavior). 321 // Not having an additional process saves some execution time of Windows, 322 // and makes debugging and profiling easier. 323 bool UseNewCC1Process = CLANG_SPAWN_CC1; 324 for (const char *Arg : Args) 325 UseNewCC1Process = llvm::StringSwitch<bool>(Arg) 326 .Case("-fno-integrated-cc1", true) 327 .Case("-fintegrated-cc1", false) 328 .Default(UseNewCC1Process); 329 330 std::unique_ptr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(Args); 331 // Driver's diagnostics don't use suppression mappings, so don't bother 332 // parsing them. CC1 still receives full args, so this doesn't impact other 333 // actions. 334 DiagOpts->DiagnosticSuppressionMappingsFile.clear(); 335 336 TextDiagnosticPrinter *DiagClient = 337 new TextDiagnosticPrinter(llvm::errs(), *DiagOpts); 338 FixupDiagPrefixExeName(DiagClient, ProgName); 339 340 DiagnosticsEngine Diags(DiagnosticIDs::create(), *DiagOpts, DiagClient); 341 342 if (!DiagOpts->DiagnosticSerializationFile.empty()) { 343 auto SerializedConsumer = 344 clang::serialized_diags::create(DiagOpts->DiagnosticSerializationFile, 345 *DiagOpts, /*MergeChildRecords=*/true); 346 Diags.setClient(new ChainedDiagnosticConsumer( 347 Diags.takeClient(), std::move(SerializedConsumer))); 348 } 349 350 ProcessWarningOptions(Diags, *DiagOpts, *VFS, /*ReportDiags=*/false); 351 352 Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags, 353 /*Title=*/"clang LLVM compiler", VFS); 354 auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(ProgName); 355 TheDriver.setTargetAndMode(TargetAndMode); 356 // If -canonical-prefixes is set, GetExecutablePath will have resolved Path 357 // to the llvm driver binary, not clang. In this case, we need to use 358 // PrependArg which should be clang-*. Checking just CanonicalPrefixes is 359 // safe even in the normal case because PrependArg will be null so 360 // setPrependArg will be a no-op. 361 if (ToolContext.NeedsPrependArg || CanonicalPrefixes) 362 TheDriver.setPrependArg(ToolContext.PrependArg); 363 364 insertTargetAndModeArgs(TargetAndMode, Args, SavedStrings); 365 366 if (!SetBackdoorDriverOutputsFromEnvVars(TheDriver)) 367 return 1; 368 369 auto ExecuteCC1WithContext = [&ToolContext, 370 &VFS](SmallVectorImpl<const char *> &ArgV) { 371 return ExecuteCC1Tool(ArgV, ToolContext, VFS); 372 }; 373 if (!UseNewCC1Process) { 374 TheDriver.CC1Main = ExecuteCC1WithContext; 375 // Ensure the CC1Command actually catches cc1 crashes 376 llvm::CrashRecoveryContext::Enable(); 377 } 378 379 std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args)); 380 381 Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash; 382 if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) { 383 auto Level = 384 llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue()) 385 .Case("off", Driver::ReproLevel::Off) 386 .Case("crash", Driver::ReproLevel::OnCrash) 387 .Case("error", Driver::ReproLevel::OnError) 388 .Case("always", Driver::ReproLevel::Always) 389 .Default(std::nullopt); 390 if (!Level) { 391 llvm::errs() << "Unknown value for " << A->getSpelling() << ": '" 392 << A->getValue() << "'\n"; 393 return 1; 394 } 395 ReproLevel = *Level; 396 } 397 if (!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) 398 ReproLevel = Driver::ReproLevel::Always; 399 400 int Res = 1; 401 bool IsCrash = false; 402 Driver::CommandStatus CommandStatus = Driver::CommandStatus::Ok; 403 // Pretend the first command failed if ReproStatus is Always. 404 const Command *FailingCommand = nullptr; 405 if (!C->getJobs().empty()) 406 FailingCommand = &*C->getJobs().begin(); 407 if (C && !C->containsError()) { 408 SmallVector<std::pair<int, const Command *>, 4> FailingCommands; 409 Res = TheDriver.ExecuteCompilation(*C, FailingCommands); 410 411 for (const auto &P : FailingCommands) { 412 int CommandRes = P.first; 413 FailingCommand = P.second; 414 if (!Res) 415 Res = CommandRes; 416 417 // If result status is < 0, then the driver command signalled an error. 418 // If result status is 70, then the driver command reported a fatal error. 419 // On Windows, abort will return an exit code of 3. In these cases, 420 // generate additional diagnostic information if possible. 421 IsCrash = CommandRes < 0 || CommandRes == 70; 422 #ifdef _WIN32 423 IsCrash |= CommandRes == 3; 424 #endif 425 #if LLVM_ON_UNIX 426 // When running in integrated-cc1 mode, the CrashRecoveryContext returns 427 // the same codes as if the program crashed. See section "Exit Status for 428 // Commands": 429 // https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html 430 IsCrash |= CommandRes > 128; 431 #endif 432 CommandStatus = 433 IsCrash ? Driver::CommandStatus::Crash : Driver::CommandStatus::Error; 434 if (IsCrash) 435 break; 436 } 437 } 438 439 // Print the bug report message that would be printed if we did actually 440 // crash, but only if we're crashing due to FORCE_CLANG_DIAGNOSTICS_CRASH. 441 if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) 442 llvm::dbgs() << llvm::getBugReportMsg(); 443 if (FailingCommand != nullptr && 444 TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel, 445 *C, *FailingCommand)) 446 Res = 1; 447 448 Diags.getClient()->finish(); 449 450 if (!UseNewCC1Process && IsCrash) { 451 // When crashing in -fintegrated-cc1 mode, bury the timer pointers, because 452 // the internal linked list might point to already released stack frames. 453 llvm::BuryPointer(llvm::TimerGroup::acquireTimerGlobals()); 454 } else { 455 // If any timers were active but haven't been destroyed yet, print their 456 // results now. This happens in -disable-free mode. 457 llvm::TimerGroup::printAll(llvm::errs()); 458 llvm::TimerGroup::clearAll(); 459 } 460 461 #ifdef _WIN32 462 // Exit status should not be negative on Win32, unless abnormal termination. 463 // Once abnormal termination was caught, negative status should not be 464 // propagated. 465 if (Res < 0) 466 Res = 1; 467 #endif 468 469 // If we have multiple failing commands, we return the result of the first 470 // failing command. 471 return Res; 472 } 473 474 extern "C" int ZigClang_main(int, char **); 475 int ZigClang_main(int argc, char **argv) { 476 return clang_main(argc, argv, {argv[0], nullptr, false}); 477 } 478