int main() { llvm::raw_fd_ostream out_stream(1, false); DiagnosticOptions diag_options; TextDiagnosticPrinter *diagClient = new TextDiagnosticPrinter(out_stream, diag_options); Diagnostic diags(diagClient); LangOptions opts; TargetOptions target_opts; target_opts.Triple = LLVM_HOSTTRIPLE; TargetInfo *target = TargetInfo::CreateTargetInfo(diags, target_opts); FileManager fm; SourceManager sm(diags); HeaderSearch headers(fm); Preprocessor pp(diags, opts, *target, sm, headers); PreprocessorOptions preprocessor_options; HeaderSearchOptions header_search_options; FrontendOptions frontend_options; InitializePreprocessor( pp, preprocessor_options, header_search_options, frontend_options); FileEntry const *file = fm.getFile("test.cpp"); FileID main_file = sm.createMainFileID(file); diagClient->BeginSourceFile(opts, &pp); pp.EnterMainSourceFile(); bool invalid = false; llvm::StringRef sr = sm.getBufferData(main_file, &invalid); (void) sr; Token tok; do { pp.Lex(tok); if (diags.hasErrorOccurred()) { break; } pp.DumpToken(tok); cerr << endl; } while (tok.isNot(tok::eof)); }
int main(int argc_, const char **argv_) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc_, argv_); std::set<std::string> SavedStrings; SmallVector<const char*, 256> argv; ExpandArgv(argc_, argv_, argv, SavedStrings); // Handle -cc1 integrated tools. if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) { StringRef Tool = argv[1] + 4; if (Tool == "") return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); if (Tool == "as") return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); // Reject unknown tools. llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n"; return 1; } bool CanonicalPrefixes = true; for (int i = 1, size = argv.size(); i < size; ++i) { if (StringRef(argv[i]) == "-no-canonical-prefixes") { CanonicalPrefixes = false; break; } } llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions; { // Note that ParseDiagnosticArgs() uses the cc1 option table. OwningPtr<OptTable> CC1Opts(createDriverOptTable()); unsigned MissingArgIndex, MissingArgCount; OwningPtr<InputArgList> Args(CC1Opts->ParseArgs(argv.begin()+1, argv.end(), MissingArgIndex, MissingArgCount)); // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. // Any errors that would be diagnosed here will also be diagnosed later, // when the DiagnosticsEngine actually exists. (void) ParseDiagnosticArgs(*DiagOpts, *Args); } // Now we can create the DiagnosticsEngine with a properly-filled-out // DiagnosticOptions instance. TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); DiagClient->setPrefix(llvm::sys::path::stem(Path.str())); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); ProcessWarningOptions(Diags, *DiagOpts); Driver TheDriver(Path.str(), llvm::sys::getDefaultTargetTriple(), "a.out", Diags); // Attempt to find the original path used to invoke the driver, to determine // the installed path. We do this manually, because we want to support that // path being a symlink. { SmallString<128> InstalledPath(argv[0]); // Do a PATH lookup, if there are no directory components. if (llvm::sys::path::filename(InstalledPath) == InstalledPath) { llvm::sys::Path Tmp = llvm::sys::Program::FindProgramByName( llvm::sys::path::filename(InstalledPath.str())); if (!Tmp.empty()) InstalledPath = Tmp.str(); } llvm::sys::fs::make_absolute(InstalledPath); InstalledPath = llvm::sys::path::parent_path(InstalledPath); bool exists; if (!llvm::sys::fs::exists(InstalledPath.str(), exists) && exists) TheDriver.setInstalledDir(InstalledPath); } llvm::InitializeAllTargets(); ParseProgName(argv, SavedStrings, TheDriver); // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE. TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS"); if (TheDriver.CCPrintOptions) TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE"); // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE. TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS"); if (TheDriver.CCPrintHeaders) TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE"); // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE. TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS"); if (TheDriver.CCLogDiagnostics) TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE"); // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a // command line behind the scenes. if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) { // FIXME: Driver shouldn't take extra initial argument. ApplyQAOverride(argv, OverrideStr, SavedStrings); } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) { // FIXME: Driver shouldn't take extra initial argument. std::vector<const char*> ExtraArgs; for (;;) { const char *Next = strchr(Cur, ','); if (Next) { ExtraArgs.push_back(SaveStringInSet(SavedStrings, std::string(Cur, Next))); Cur = Next + 1; } else { if (*Cur != '\0') ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur)); break; } } argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end()); } OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv)); int Res = 0; const Command *FailingCommand = 0; if (C.get()) Res = TheDriver.ExecuteCompilation(*C, FailingCommand); // Force a crash to test the diagnostics. if(::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) Res = -1; // If result status is < 0, then the driver command signalled an error. // If result status is 70, then the driver command reported a fatal error. // In these cases, generate additional diagnostic information if possible. if (Res < 0 || Res == 70) TheDriver.generateCompilationDiagnostics(*C, FailingCommand); // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); llvm::llvm_shutdown(); #ifdef _WIN32 // Exit status should not be negative on Win32, unless abnormal termination. // Once abnormal termiation was caught, negative status should not be // propagated. if (Res < 0) Res = 1; #endif return Res; }
int cc1as_main(const char **ArgBegin, const char **ArgEnd, const char *Argv0, void *MainAddr) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin); llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. // Initialize targets and assembly printers/parsers. InitializeAllTargetInfos(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); // Construct our diagnostic client. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(errs(), &*DiagOpts); DiagClient->setPrefix("clang -cc1as"); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); // Set an error handler, so that any LLVM backend diagnostics go through our // error handler. ScopedFatalErrorHandler FatalErrorHandler (LLVMErrorHandler, static_cast<void*>(&Diags)); // Parse the arguments. AssemblerInvocation Asm; if (!AssemblerInvocation::CreateFromArgs(Asm, ArgBegin, ArgEnd, Diags)) return 1; // Honor -help. if (Asm.ShowHelp) { std::unique_ptr<OptTable> Opts(driver::createCC1AsOptTable()); Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler"); return 0; } // Honor -version. // // FIXME: Use a better -version message? if (Asm.ShowVersion) { llvm::cl::PrintVersionMessage(); return 0; } // Honor -mllvm. // // FIXME: Remove this, one day. if (!Asm.LLVMArgs.empty()) { unsigned NumArgs = Asm.LLVMArgs.size(); const char **Args = new const char*[NumArgs + 2]; Args[0] = "clang (LLVM option parsing)"; for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Asm.LLVMArgs[i].c_str(); Args[NumArgs + 1] = 0; llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args); } // Execute the invocation, unless there were parsing errors. bool Success = false; if (!Diags.hasErrorOccurred()) Success = ExecuteAssembler(Asm, Diags); // If any timers were active but haven't been destroyed yet, print their // results now. TimerGroup::printAll(errs()); return !Success; }
int main(int argc_, const char **argv_) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc_, argv_); SmallVector<const char *, 256> argv; llvm::SpecificBumpPtrAllocator<char> ArgAllocator; std::error_code EC = llvm::sys::Process::GetArgumentVector( argv, ArrayRef<const char *>(argv_, argc_), ArgAllocator); if (EC) { llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n'; return 1; } std::set<std::string> SavedStrings; StringSetSaver Saver(SavedStrings); llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv); // Handle -cc1 integrated tools. if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) { StringRef Tool = argv[1] + 4; if (Tool == "") return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); if (Tool == "as") return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); // Reject unknown tools. llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n"; return 1; } bool CanonicalPrefixes = true; for (int i = 1, size = argv.size(); i < size; ++i) { if (StringRef(argv[i]) == "-no-canonical-prefixes") { CanonicalPrefixes = false; break; } } // Handle CCC_OVERRIDE_OPTIONS, used for editing a command line behind the // scenes. if (const char *OverrideStr = ::getenv("CCC_OVERRIDE_OPTIONS")) { // FIXME: Driver shouldn't take extra initial argument. ApplyQAOverride(argv, OverrideStr, SavedStrings); } std::string Path = GetExecutablePath(argv[0], CanonicalPrefixes); IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions; { std::unique_ptr<OptTable> Opts(createDriverOptTable()); unsigned MissingArgIndex, MissingArgCount; std::unique_ptr<InputArgList> Args(Opts->ParseArgs( argv.begin() + 1, argv.end(), MissingArgIndex, MissingArgCount)); // We ignore MissingArgCount and the return value of ParseDiagnosticArgs. // Any errors that would be diagnosed here will also be diagnosed later, // when the DiagnosticsEngine actually exists. (void) ParseDiagnosticArgs(*DiagOpts, *Args); } // Now we can create the DiagnosticsEngine with a properly-filled-out // DiagnosticOptions instance. TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); // If the clang binary happens to be named cl.exe for compatibility reasons, // use clang-cl.exe as the prefix to avoid confusion between clang and MSVC. StringRef ExeBasename(llvm::sys::path::filename(Path)); if (ExeBasename.equals_lower("cl.exe")) ExeBasename = "clang-cl.exe"; DiagClient->setPrefix(ExeBasename); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); // Attempt to find the original path used to invoke the driver, to determine // the installed path. We do this manually, because we want to support that // path being a symlink. { SmallString<128> InstalledPath(argv[0]); // Do a PATH lookup, if there are no directory components. if (llvm::sys::path::filename(InstalledPath) == InstalledPath) { std::string Tmp = llvm::sys::FindProgramByName( llvm::sys::path::filename(InstalledPath.str())); if (!Tmp.empty()) InstalledPath = Tmp; } llvm::sys::fs::make_absolute(InstalledPath); InstalledPath = llvm::sys::path::parent_path(InstalledPath); bool exists; if (!llvm::sys::fs::exists(InstalledPath.str(), exists) && exists) TheDriver.setInstalledDir(InstalledPath); } llvm::InitializeAllTargets(); ParseProgName(argv, SavedStrings, TheDriver); // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE. TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS"); if (TheDriver.CCPrintOptions) TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE"); // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE. TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS"); if (TheDriver.CCPrintHeaders) TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE"); // Handle CC_LOG_DIAGNOSTICS and CC_LOG_DIAGNOSTICS_FILE. TheDriver.CCLogDiagnostics = !!::getenv("CC_LOG_DIAGNOSTICS"); if (TheDriver.CCLogDiagnostics) TheDriver.CCLogDiagnosticsFilename = ::getenv("CC_LOG_DIAGNOSTICS_FILE"); std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(argv)); int Res = 0; SmallVector<std::pair<int, const Command *>, 4> FailingCommands; if (C.get()) Res = TheDriver.ExecuteCompilation(*C, FailingCommands); // Force a crash to test the diagnostics. if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH")) { Diags.Report(diag::err_drv_force_crash) << "FORCE_CLANG_DIAGNOSTICS_CRASH"; const Command *FailingCommand = nullptr; FailingCommands.push_back(std::make_pair(-1, FailingCommand)); } for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it = FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) { int CommandRes = it->first; const Command *FailingCommand = it->second; if (!Res) Res = CommandRes; // If result status is < 0, then the driver command signalled an error. // If result status is 70, then the driver command reported a fatal error. // On Windows, abort will return an exit code of 3. In these cases, // generate additional diagnostic information if possible. bool DiagnoseCrash = CommandRes < 0 || CommandRes == 70; #ifdef LLVM_ON_WIN32 DiagnoseCrash |= CommandRes == 3; #endif if (DiagnoseCrash) { TheDriver.generateCompilationDiagnostics(*C, FailingCommand); break; } } // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); llvm::llvm_shutdown(); #ifdef LLVM_ON_WIN32 // Exit status should not be negative on Win32, unless abnormal termination. // Once abnormal termiation was caught, negative status should not be // propagated. if (Res < 0) Res = 1; #endif // If we have multiple failing commands, we return the result of the first // failing command. return Res; }
int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) { // Initialize targets and assembly printers/parsers. InitializeAllTargetInfos(); InitializeAllTargetMCs(); InitializeAllAsmParsers(); // Construct our diagnostic client. IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(errs(), &*DiagOpts); DiagClient->setPrefix("clang -cc1as"); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); // Set an error handler, so that any LLVM backend diagnostics go through our // error handler. ScopedFatalErrorHandler FatalErrorHandler (LLVMErrorHandler, static_cast<void*>(&Diags)); // Parse the arguments. AssemblerInvocation Asm; if (!AssemblerInvocation::CreateFromArgs(Asm, Argv, Diags)) return 1; if (Asm.ShowHelp) { std::unique_ptr<OptTable> Opts(driver::createDriverOptTable()); Opts->PrintHelp(llvm::outs(), "clang -cc1as [options] file...", "Clang Integrated Assembler", /*Include=*/driver::options::CC1AsOption, /*Exclude=*/0, /*ShowAllAliases=*/false); return 0; } // Honor -version. // // FIXME: Use a better -version message? if (Asm.ShowVersion) { llvm::cl::PrintVersionMessage(); return 0; } // Honor -mllvm. // // FIXME: Remove this, one day. if (!Asm.LLVMArgs.empty()) { unsigned NumArgs = Asm.LLVMArgs.size(); auto Args = llvm::make_unique<const char*[]>(NumArgs + 2); Args[0] = "clang (LLVM option parsing)"; for (unsigned i = 0; i != NumArgs; ++i) Args[i + 1] = Asm.LLVMArgs[i].c_str(); Args[NumArgs + 1] = nullptr; llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get()); } // Execute the invocation, unless there were parsing errors. bool Failed = Diags.hasErrorOccurred() || ExecuteAssembler(Asm, Diags); // If any timers were active but haven't been destroyed yet, print their // results now. TimerGroup::printAll(errs()); return !!Failed; }
int main(int argc_, const char **argv_) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc_, argv_); std::set<std::string> SavedStrings; llvm::SmallVector<const char*, 256> argv; ExpandArgv(argc_, argv_, argv, SavedStrings); // Handle -cc1 integrated tools. if (argv.size() > 1 && llvm::StringRef(argv[1]).startswith("-cc1")) { llvm::StringRef Tool = argv[1] + 4; if (Tool == "") return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); if (Tool == "as") return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0], (void*) (intptr_t) GetExecutablePath); // Reject unknown tools. llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n"; return 1; } bool CanonicalPrefixes = true; for (int i = 1, size = argv.size(); i < size; ++i) { if (llvm::StringRef(argv[i]) == "-no-canonical-prefixes") { CanonicalPrefixes = false; break; } } llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); DiagClient->setPrefix(llvm::sys::path::stem(Path.str())); llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); Diagnostic Diags(DiagID, DiagClient); #ifdef CLANG_IS_PRODUCTION const bool IsProduction = true; # ifdef CLANGXX_IS_PRODUCTION const bool CXXIsProduction = true; # else const bool CXXIsProduction = false; # endif #else const bool IsProduction = false; const bool CXXIsProduction = false; #endif Driver TheDriver(Path.str(), llvm::sys::getHostTriple(), "a.out", IsProduction, CXXIsProduction, Diags); // Attempt to find the original path used to invoke the driver, to determine // the installed path. We do this manually, because we want to support that // path being a symlink. { llvm::SmallString<128> InstalledPath(argv[0]); // Do a PATH lookup, if there are no directory components. if (llvm::sys::path::filename(InstalledPath) == InstalledPath) { llvm::sys::Path Tmp = llvm::sys::Program::FindProgramByName( llvm::sys::path::filename(InstalledPath.str())); if (!Tmp.empty()) InstalledPath = Tmp.str(); } llvm::sys::fs::make_absolute(InstalledPath); InstalledPath = llvm::sys::path::parent_path(InstalledPath); bool exists; if (!llvm::sys::fs::exists(InstalledPath.str(), exists) && exists) TheDriver.setInstalledDir(InstalledPath); } // Check for ".*++" or ".*++-[^-]*" to determine if we are a C++ // compiler. This matches things like "c++", "clang++", and "clang++-1.1". // // Note that we intentionally want to use argv[0] here, to support "clang++" // being a symlink. // // We use *argv instead of argv[0] to work around a bogus g++ warning. const char *progname = argv_[0]; std::string ProgName(llvm::sys::path::stem(progname)); if (llvm::StringRef(ProgName).endswith("++") || llvm::StringRef(ProgName).rsplit('-').first.endswith("++")) { TheDriver.CCCIsCXX = true; } // Handle CC_PRINT_OPTIONS and CC_PRINT_OPTIONS_FILE. TheDriver.CCPrintOptions = !!::getenv("CC_PRINT_OPTIONS"); if (TheDriver.CCPrintOptions) TheDriver.CCPrintOptionsFilename = ::getenv("CC_PRINT_OPTIONS_FILE"); // Handle CC_PRINT_HEADERS and CC_PRINT_HEADERS_FILE. TheDriver.CCPrintHeaders = !!::getenv("CC_PRINT_HEADERS"); if (TheDriver.CCPrintHeaders) TheDriver.CCPrintHeadersFilename = ::getenv("CC_PRINT_HEADERS_FILE"); // Handle QA_OVERRIDE_GCC3_OPTIONS and CCC_ADD_ARGS, used for editing a // command line behind the scenes. if (const char *OverrideStr = ::getenv("QA_OVERRIDE_GCC3_OPTIONS")) { // FIXME: Driver shouldn't take extra initial argument. ApplyQAOverride(argv, OverrideStr, SavedStrings); } else if (const char *Cur = ::getenv("CCC_ADD_ARGS")) { // FIXME: Driver shouldn't take extra initial argument. std::vector<const char*> ExtraArgs; for (;;) { const char *Next = strchr(Cur, ','); if (Next) { ExtraArgs.push_back(SaveStringInSet(SavedStrings, std::string(Cur, Next))); Cur = Next + 1; } else { if (*Cur != '\0') ExtraArgs.push_back(SaveStringInSet(SavedStrings, Cur)); break; } } argv.insert(&argv[1], ExtraArgs.begin(), ExtraArgs.end()); } llvm::OwningPtr<Compilation> C(TheDriver.BuildCompilation(argv.size(), &argv[0])); int Res = 0; if (C.get()) Res = TheDriver.ExecuteCompilation(*C); // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); llvm::llvm_shutdown(); return Res; }
int main(int argc_, const char **argv_) { llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc_, argv_); SmallVector<const char *, 256> argv; llvm::SpecificBumpPtrAllocator<char> ArgAllocator; std::error_code EC = llvm::sys::Process::GetArgumentVector( argv, llvm::makeArrayRef(argv_, argc_), ArgAllocator); if (EC) { llvm::errs() << "error: couldn't get arguments: " << EC.message() << '\n'; return 1; } std::set<std::string> SavedStrings; StringSetSaver Saver(SavedStrings); // Determines whether we want nullptr markers in clang_argv to indicate response // files end-of-lines. We only use this for the /LINK driver argument. bool MarkEOLs = true; if (argv.size() > 1 && StringRef(argv[1]).startswith("-cc1")) MarkEOLs = false; llvm::cl::ExpandResponseFiles(Saver, llvm::cl::TokenizeGNUCommandLine, argv, MarkEOLs); // Separate out templight and clang flags. templight flags are "-Xtemplight <templight_flag>" SmallVector<const char *, 256> templight_argv, clang_argv; templight_argv.push_back(argv[0]); clang_argv.push_back(argv[0]); for (int i = 1, size = argv.size(); i < size; /* in loop */ ) { if ((argv[i] != nullptr) && (strcmp(argv[i], "-Xtemplight") == 0)) { while( i < size - 1 && argv[++i] == nullptr ) /* skip EOLs */ ; templight_argv.push_back(argv[i]); // the word after -Xtemplight if( i == size - 1 ) // was this the last argument? break; while( i < size - 1 && argv[++i] == nullptr ) /* skip EOLs */ ; } else { if ((argv[i] != nullptr) && ((strcmp(argv[i], "-help") == 0) || (strcmp(argv[i], "--help") == 0))) { // Print the help for the templight options: PrintTemplightHelp(); } clang_argv.push_back(argv[i++]); // also leave -help to driver (to print its help info too) } } cl::ParseCommandLineOptions( templight_argv.size(), &templight_argv[0], "A tool to profile template instantiations in C++ code.\n"); bool CanonicalPrefixes = true; for (int i = 1, size = clang_argv.size(); i < size; ++i) { // Skip end-of-line response file markers if (clang_argv[i] == nullptr) continue; if (StringRef(clang_argv[i]) == "-no-canonical-prefixes") { CanonicalPrefixes = false; break; } } std::string Path = GetExecutablePath(clang_argv[0], CanonicalPrefixes); IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = CreateAndPopulateDiagOpts(clang_argv); TextDiagnosticPrinter *DiagClient = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts); DiagClient->setPrefix(llvm::sys::path::filename(Path)); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagClient); ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false); // Prepare a variable for the return value: int Res = 0; void *GetExecutablePathVP = (void *)(intptr_t) GetExecutablePath; llvm::InitializeAllTargets(); llvm::InitializeAllTargetMCs(); llvm::InitializeAllAsmPrinters(); llvm::InitializeAllAsmParsers(); #ifdef LINK_POLLY_INTO_TOOLS llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry(); polly::initializePollyPasses(Registry); #endif // Handle -cc1 integrated tools, even if -cc1 was expanded from a response // file. auto FirstArg = std::find_if(clang_argv.begin() + 1, clang_argv.end(), [](const char *A) { return A != nullptr; }); bool invokeCC1 = (FirstArg != clang_argv.end() && StringRef(*FirstArg).startswith("-cc1")); if (invokeCC1) { // If -cc1 came from a response file, remove the EOL sentinels. if (MarkEOLs) { auto newEnd = std::remove(clang_argv.begin(), clang_argv.end(), nullptr); clang_argv.resize(newEnd - clang_argv.begin()); } std::unique_ptr<CompilerInstance> Clang(new CompilerInstance()); Res = !CompilerInvocation::CreateFromArgs( Clang->getInvocation(), clang_argv.begin() + 2, clang_argv.end(), Diags); // Infer the builtin include path if unspecified. if (Clang->getHeaderSearchOpts().UseBuiltinIncludes && Clang->getHeaderSearchOpts().ResourceDir.empty()) Clang->getHeaderSearchOpts().ResourceDir = CompilerInvocation::GetResourcesPath(clang_argv[0], GetExecutablePathVP); // Create the compilers actual diagnostics engine. Clang->createDiagnostics(); if (!Clang->hasDiagnostics()) { Res = 1; goto cleanup; } LocalOutputFilename = OutputFilename; // Execute the frontend actions. Res = ExecuteTemplightInvocation(Clang.get()); // When running with -disable-free, don't do any destruction or shutdown. if (Clang->getFrontendOpts().DisableFree) { if (llvm::AreStatisticsEnabled() || Clang->getFrontendOpts().ShowStats) llvm::PrintStatistics(); BuryPointer(std::move(Clang)); } } else { Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags); TheDriver.setTitle("templight"); SetInstallDir(clang_argv, TheDriver); ParseProgName(clang_argv, SavedStrings, TheDriver); SetBackdoorDriverOutputsFromEnvVars(TheDriver); std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(clang_argv)); if(!C.get()) { Res = 1; goto cleanup; } SmallVector<std::pair<int, const Command *>, 4> FailingCommands; ExecuteTemplightJobs(TheDriver, Diags, *C, C->getJobs(), clang_argv[0], FailingCommands); // Merge all the temp files into a single output file: if ( ! TempOutputFiles.empty() ) { if ( OutputFilename.empty() ) OutputFilename = "a"; std::string FinalOutputFilename = TemplightAction::CreateOutputFilename( nullptr, OutputFilename, InstProfiler, OutputToStdOut, MemoryProfile); if ( ( !FinalOutputFilename.empty() ) && ( FinalOutputFilename != "-" ) ) { std::error_code error; llvm::raw_fd_ostream TraceOS(FinalOutputFilename, error, llvm::sys::fs::F_None); if ( error ) { llvm::errs() << "Error: [Templight] Can not open file to write trace of template instantiations: " << FinalOutputFilename << " Error: " << error.message(); } else { for ( SmallVector< std::string, 32 >::iterator it = TempOutputFiles.begin(), it_end = TempOutputFiles.end(); it != it_end; ++it) { llvm::ErrorOr< std::unique_ptr<llvm::MemoryBuffer> > file_epbuf = llvm::MemoryBuffer::getFile(llvm::Twine(*it)); if(file_epbuf && file_epbuf.get()) { TraceOS << StringRef(file_epbuf.get()->getBufferStart(), file_epbuf.get()->getBufferEnd() - file_epbuf.get()->getBufferStart()) << '\n'; } } } } } // Remove temp files. C->CleanupFileList(C->getTempFiles()); // If the command succeeded, the number of failing commands should zero: Res = FailingCommands.size(); // Otherwise, remove result files and print extra information about abnormal // failures. for (SmallVectorImpl< std::pair<int, const Command *> >::iterator it = FailingCommands.begin(), ie = FailingCommands.end(); it != ie; ++it) { int FailRes = it->first; const Command *FailingCommand = it->second; // Remove result files if we're not saving temps. if (!C->getArgs().hasArg(options::OPT_save_temps)) { const JobAction *JA = cast<JobAction>(&FailingCommand->getSource()); C->CleanupFileMap(C->getResultFiles(), JA, true); // Failure result files are valid unless we crashed. if (FailRes < 0) C->CleanupFileMap(C->getFailureResultFiles(), JA, true); } // Print extra information about abnormal failures, if possible. const Tool &FailingTool = FailingCommand->getCreator(); if (!FailingCommand->getCreator().hasGoodDiagnostics() || FailRes != 1) { if (FailRes < 0) Diags.Report(clang::diag::err_drv_command_signalled) << FailingTool.getShortName(); else Diags.Report(clang::diag::err_drv_command_failed) << FailingTool.getShortName() << FailRes; } } } cleanup: // If any timers were active but haven't been destroyed yet, print their // results now. This happens in -disable-free mode. llvm::TimerGroup::printAll(llvm::errs()); llvm::llvm_shutdown(); #ifdef LLVM_ON_WIN32 // Exit status should not be negative on Win32, unless abnormal termination. // Once abnormal termiation was caught, negative status should not be // propagated. if (Res < 0) Res = 1; #endif // If we have multiple failing commands, we return the result of the first // failing command. return Res; }