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