Index: include/clang/Driver/CC1AsOptions.td =================================================================== --- include/clang/Driver/CC1AsOptions.td (revision 126559) +++ include/clang/Driver/CC1AsOptions.td (working copy) @@ -72,4 +72,11 @@ HelpText<"Relax all fixups (for performance testing)">; def no_exec_stack : Flag<"--noexecstack">, - HelpText<"Mark the file as not needing an executable stack">; \ No newline at end of file + HelpText<"Mark the file as not needing an executable stack">; + +//===----------------------------------------------------------------------===// +// Diagnostic Options +//===----------------------------------------------------------------------===// + +def output_diagnostics_as_debug_string : Flag<"-output-diagnostics-as-debug-string">, + HelpText<"Output all diagnostic and other information to debug output intstead of stdout/stderr">; \ No newline at end of file Index: include/clang/Driver/CC1Options.td =================================================================== --- include/clang/Driver/CC1Options.td (revision 126559) +++ include/clang/Driver/CC1Options.td (working copy) @@ -217,6 +217,8 @@ def w : Flag<"-w">, HelpText<"Suppress all warnings">; def pedantic : Flag<"-pedantic">; def pedantic_errors : Flag<"-pedantic-errors">; +def output_diagnostics_as_debug_string : Flag<"-output-diagnostics-as-debug-string"> + , HelpText<"Output all diagnostic and other information to debug output intstead of stdout/stderr">; // This gets all -W options, including -Werror, -W[no-]system-headers, etc. The // driver has stripped off -Wa,foo etc. The driver has also translated -W to Index: include/clang/Driver/Compilation.h =================================================================== --- include/clang/Driver/Compilation.h (revision 126559) +++ include/clang/Driver/Compilation.h (working copy) @@ -28,6 +28,17 @@ class JobList; class ToolChain; +typedef int (*MainFunctionPointer)(int argc_, const char **argv_); + +class CompilationThisProgramScope { + MainFunctionPointer OldThisProgramMain; + const char *OldThisProgramExecutable; +public: + CompilationThisProgramScope(MainFunctionPointer ThisProgramMain, + const char *ThisProgramExecutable); + ~CompilationThisProgramScope(); +}; + /// Compilation - A set of tasks to perform for a single driver /// invocation. class Compilation { @@ -61,6 +72,12 @@ /// Result files which should be removed on failure. ArgStringList ResultFiles; + /// Used to take a shortcut in recursive program execution if + /// requested with CompilationThisProgramScope. + friend class CompilationThisProgramScope; + static MainFunctionPointer ThisProgramMain; + static const char *ThisProgramExecutable; + public: Compilation(const Driver &D, const ToolChain &DefaultToolChain, InputArgList *Args, DerivedArgList *TranslatedArgs); Index: include/clang/Driver/Driver.h =================================================================== --- include/clang/Driver/Driver.h (revision 126559) +++ include/clang/Driver/Driver.h (working copy) @@ -257,10 +257,10 @@ /// PrintHelp - Print the help text. /// /// \param ShowHidden - Show hidden options. - void PrintHelp(bool ShowHidden) const; + void PrintHelp(bool ShowHidden, llvm::raw_ostream &OS) const; /// PrintOptions - Print the list of arguments. - void PrintOptions(const ArgList &Args) const; + void PrintOptions(const ArgList &Args, llvm::raw_ostream &OS) const; /// PrintVersion - Print the driver version. void PrintVersion(const Compilation &C, llvm::raw_ostream &OS) const; Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td (revision 126559) +++ include/clang/Driver/Options.td (working copy) @@ -116,6 +116,8 @@ // Standard Options +def output_diagnostics_as_debug_string : Flag<"-output-diagnostics-as-debug-string"> + , HelpText<"Output all diagnostic and other information to debug output intstead of stdout/stderr">; def _HASH_HASH_HASH : Flag<"-###">, Flags<[DriverOption]>, HelpText<"Print the commands to run for this compilation">; def A : JoinedOrSeparate<"-A">; Index: include/clang/Frontend/CompilerInstance.h =================================================================== --- include/clang/Frontend/CompilerInstance.h (revision 126559) +++ include/clang/Frontend/CompilerInstance.h (working copy) @@ -141,14 +141,12 @@ /// Note that this routine may write output to 'stderr'. /// /// \param Act - The action to execute. + /// \param OS - The out stream to write any debugging verbose output to /// \return - True on success. // - // FIXME: This function should take the stream to write any debugging / - // verbose output to as an argument. - // // FIXME: Eliminate the llvm_shutdown requirement, that should either be part // of the context or else not CompilerInstance specific. - bool ExecuteAction(FrontendAction &Act); + bool ExecuteAction(FrontendAction &Act, llvm::raw_ostream &OS); /// } /// @name Compiler Invocation and Options Index: include/clang/Frontend/DiagnosticOptions.h =================================================================== --- include/clang/Frontend/DiagnosticOptions.h (revision 126559) +++ include/clang/Frontend/DiagnosticOptions.h (working copy) @@ -41,6 +41,8 @@ unsigned VerifyDiagnostics: 1; /// Check that diagnostics match the expected /// diagnostics, indicated by markers in the /// input source file. + unsigned OutputDiagnosticsAsDebugString : 1; /// Output diagnostics + /// as debug strings. unsigned ErrorLimit; /// Limit # errors emitted. unsigned MacroBacktraceLimit; /// Limit depth of macro instantiation @@ -83,6 +85,7 @@ ShowSourceRanges = 0; ShowParseableFixits = 0; VerifyDiagnostics = 0; + OutputDiagnosticsAsDebugString = 0; ErrorLimit = 0; TemplateBacktraceLimit = DefaultTemplateBacktraceLimit; MacroBacktraceLimit = DefaultMacroBacktraceLimit; Index: include/clang/FrontendTool/Utils.h =================================================================== --- include/clang/FrontendTool/Utils.h (revision 126559) +++ include/clang/FrontendTool/Utils.h (working copy) @@ -15,15 +15,19 @@ #ifndef LLVM_CLANG_FRONTENDTOOL_UTILS_H #define LLVM_CLANG_FRONTENDTOOL_UTILS_H +#include "llvm/Support/raw_ostream.h" + namespace clang { class CompilerInstance; /// ExecuteCompilerInvocation - Execute the given actions described by the -/// compiler invocation object in the given compiler instance. +/// Clang invocation object in the given compiler instance. +/// OutputStreams the output streams to report any errors or information to. /// /// \return - True on success. -bool ExecuteCompilerInvocation(CompilerInstance *Clang); +bool ExecuteCompilerInvocation(CompilerInstance *Clang, + llvm::raw_output_streams &OutputStreams); } // end namespace clang Index: lib/Driver/Compilation.cpp =================================================================== --- lib/Driver/Compilation.cpp (revision 126559) +++ lib/Driver/Compilation.cpp (working copy) @@ -22,6 +22,21 @@ #include using namespace clang::driver; + +CompilationThisProgramScope:: +CompilationThisProgramScope(MainFunctionPointer _ThisProgramMain, + const char *_ThisProgramExecutable) { + OldThisProgramMain = Compilation::ThisProgramMain; + OldThisProgramExecutable = Compilation::ThisProgramExecutable; + Compilation::ThisProgramMain = _ThisProgramMain; + Compilation::ThisProgramExecutable = _ThisProgramExecutable; +} +CompilationThisProgramScope::~CompilationThisProgramScope() { + Compilation::ThisProgramMain = OldThisProgramMain; + Compilation::ThisProgramExecutable = OldThisProgramExecutable; +} + + Compilation::Compilation(const Driver &D, const ToolChain &_DefaultToolChain, InputArgList *_Args, DerivedArgList *_TranslatedArgs) : TheDriver(D), DefaultToolChain(_DefaultToolChain), Args(_Args), @@ -121,13 +136,17 @@ return Success; } +MainFunctionPointer Compilation::ThisProgramMain = 0; +const char *Compilation::ThisProgramExecutable = 0; + int Compilation::ExecuteCommand(const Command &C, const Command *&FailingCommand) const { llvm::sys::Path Prog(C.getExecutable()); const char **Argv = new const char*[C.getArguments().size() + 2]; Argv[0] = C.getExecutable(); + int NumArguments = C.getArguments().size() + 1; std::copy(C.getArguments().begin(), C.getArguments().end(), Argv+1); - Argv[C.getArguments().size() + 1] = 0; + Argv[NumArguments] = 0; if (getDriver().CCCEcho || getDriver().CCPrintOptions || getArgs().hasArg(options::OPT_v)) { @@ -159,11 +178,17 @@ } std::string Error; - int Res = - llvm::sys::Program::ExecuteAndWait(Prog, Argv, + int Res; + if (ThisProgramExecutable != 0 && ThisProgramMain != 0 && + Prog == llvm::sys::Path(ThisProgramExecutable)) { + Res = ThisProgramMain(NumArguments, Argv); + } + else { + Res = llvm::sys::Program::ExecuteAndWait(Prog, Argv, /*env*/0, /*redirects*/0, /*secondsToWait*/0, /*memoryLimit*/0, &Error); + } if (!Error.empty()) { assert(Res && "Error string set with 0 result code!"); getDriver().Diag(clang::diag::err_drv_command_failure) << Error; Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp (revision 126559) +++ lib/Driver/Driver.cpp (working copy) @@ -297,9 +297,14 @@ Compilation *C = new Compilation(*this, *Host->CreateToolChain(*Args), Args, TranslatedArgs); + // FIXME: This behavior shouldn't be here. if (CCCPrintOptions) { - PrintOptions(C->getInputArgs()); + llvm::raw_output_streams *Streams = &llvm::stdstreams(); + if (C->getArgs().hasArg(options::OPT_output_diagnostics_as_debug_string)) + Streams = &llvm::debugstreams(); + + PrintOptions(C->getInputArgs(), Streams->errs()); return C; } @@ -325,8 +330,12 @@ int Driver::ExecuteCompilation(const Compilation &C) const { // Just print if -### was present. + llvm::raw_output_streams *Streams = &llvm::stdstreams(); + if (C.getArgs().hasArg(options::OPT_output_diagnostics_as_debug_string)) + Streams = &llvm::debugstreams(); + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { - C.PrintJob(llvm::errs(), C.getJobs(), "\n", true); + C.PrintJob(Streams->errs(), C.getJobs(), "\n", true); return 0; } @@ -370,25 +379,25 @@ return Res; } -void Driver::PrintOptions(const ArgList &Args) const { +void Driver::PrintOptions(const ArgList &Args, llvm::raw_ostream &OS) const { unsigned i = 0; for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it, ++i) { Arg *A = *it; - llvm::errs() << "Option " << i << " - " + OS << "Option " << i << " - " << "Name: \"" << A->getOption().getName() << "\", " << "Values: {"; for (unsigned j = 0; j < A->getNumValues(); ++j) { if (j) - llvm::errs() << ", "; - llvm::errs() << '"' << A->getValue(Args, j) << '"'; + OS << ", "; + OS << '"' << A->getValue(Args, j) << '"'; } - llvm::errs() << "}\n"; + OS << "}\n"; } } -void Driver::PrintHelp(bool ShowHidden) const { - getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(), +void Driver::PrintHelp(bool ShowHidden, llvm::raw_ostream &OS) const { + getOpts().PrintHelp(OS, Name.c_str(), DriverTitle.c_str(), ShowHidden); } @@ -417,8 +426,12 @@ // The order these options are handled in gcc is all over the place, but we // don't expect inconsistencies w.r.t. that to matter in practice. + llvm::raw_output_streams *Streams = &llvm::stdstreams(); + if (C.getArgs().hasArg(options::OPT_output_diagnostics_as_debug_string)) + Streams = &llvm::debugstreams(); + if (C.getArgs().hasArg(options::OPT_dumpmachine)) { - llvm::outs() << C.getDefaultToolChain().getTripleString() << '\n'; + Streams->outs() << C.getDefaultToolChain().getTripleString() << '\n'; return false; } @@ -429,85 +442,85 @@ // If we want to return a more correct answer some day, then we should // introduce a non-pedantically GCC compatible mode to Clang in which we // provide sensible definitions for -dumpversion, __VERSION__, etc. - llvm::outs() << "4.2.1\n"; + Streams->outs() << "4.2.1\n"; return false; } if (C.getArgs().hasArg(options::OPT__print_diagnostic_categories)) { - PrintDiagnosticCategories(llvm::outs()); + PrintDiagnosticCategories(Streams->outs()); return false; } if (C.getArgs().hasArg(options::OPT__help) || C.getArgs().hasArg(options::OPT__help_hidden)) { - PrintHelp(C.getArgs().hasArg(options::OPT__help_hidden)); + PrintHelp(C.getArgs().hasArg(options::OPT__help_hidden), Streams->outs()); return false; } if (C.getArgs().hasArg(options::OPT__version)) { // Follow gcc behavior and use stdout for --version and stderr for -v. - PrintVersion(C, llvm::outs()); + PrintVersion(C, Streams->outs()); return false; } if (C.getArgs().hasArg(options::OPT_v) || C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { - PrintVersion(C, llvm::errs()); + PrintVersion(C, Streams->errs()); SuppressMissingInputWarning = true; } const ToolChain &TC = C.getDefaultToolChain(); if (C.getArgs().hasArg(options::OPT_print_search_dirs)) { - llvm::outs() << "programs: ="; + Streams->outs() << "programs: ="; for (ToolChain::path_list::const_iterator it = TC.getProgramPaths().begin(), ie = TC.getProgramPaths().end(); it != ie; ++it) { if (it != TC.getProgramPaths().begin()) - llvm::outs() << ':'; - llvm::outs() << *it; + Streams->outs() << ':'; + Streams->outs() << *it; } - llvm::outs() << "\n"; - llvm::outs() << "libraries: ="; + Streams->outs() << "\n"; + Streams->outs() << "libraries: ="; for (ToolChain::path_list::const_iterator it = TC.getFilePaths().begin(), ie = TC.getFilePaths().end(); it != ie; ++it) { if (it != TC.getFilePaths().begin()) - llvm::outs() << ':'; - llvm::outs() << *it; + Streams->outs() << ':'; + Streams->outs() << *it; } - llvm::outs() << "\n"; + Streams->outs() << "\n"; return false; } // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) { - llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC) << "\n"; + Streams->outs() << GetFilePath(A->getValue(C.getArgs()), TC) << "\n"; return false; } if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) { - llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC) << "\n"; + Streams->outs() << GetProgramPath(A->getValue(C.getArgs()), TC) << "\n"; return false; } if (C.getArgs().hasArg(options::OPT_print_libgcc_file_name)) { - llvm::outs() << GetFilePath("libgcc.a", TC) << "\n"; + Streams->outs() << GetFilePath("libgcc.a", TC) << "\n"; return false; } if (C.getArgs().hasArg(options::OPT_print_multi_lib)) { // FIXME: We need tool chain support for this. - llvm::outs() << ".;\n"; + Streams->outs() << ".;\n"; switch (C.getDefaultToolChain().getTriple().getArch()) { default: break; case llvm::Triple::x86_64: - llvm::outs() << "x86_64;@m64" << "\n"; + Streams->outs() << "x86_64;@m64" << "\n"; break; case llvm::Triple::ppc64: - llvm::outs() << "ppc64;@m64" << "\n"; + Streams->outs() << "ppc64;@m64" << "\n"; break; } return false; @@ -521,15 +534,15 @@ default: case llvm::Triple::x86: case llvm::Triple::ppc: - llvm::outs() << "." << "\n"; + Streams->outs() << "." << "\n"; break; case llvm::Triple::x86_64: - llvm::outs() << "x86_64" << "\n"; + Streams->outs() << "x86_64" << "\n"; break; case llvm::Triple::ppc64: - llvm::outs() << "ppc64" << "\n"; + Streams->outs() << "ppc64" << "\n"; break; } return false; @@ -540,6 +553,11 @@ static unsigned PrintActions1(const Compilation &C, Action *A, std::map &Ids) { + + llvm::raw_output_streams *Streams = &llvm::stdstreams(); + if (C.getArgs().hasArg(options::OPT_output_diagnostics_as_debug_string)) + Streams = &llvm::debugstreams(); + if (Ids.count(A)) return Ids[A]; @@ -566,7 +584,7 @@ unsigned Id = Ids.size(); Ids[A] = Id; - llvm::errs() << Id << ": " << os.str() << ", " + Streams->errs() << Id << ": " << os.str() << ", " << types::getTypeName(A->getType()) << "\n"; return Id; @@ -1104,6 +1122,10 @@ InputInfo &Result) const { llvm::PrettyStackTraceString CrashInfo("Building compilation jobs"); + llvm::raw_output_streams *Streams = &llvm::stdstreams(); + if (C.getArgs().hasArg(options::OPT_output_diagnostics_as_debug_string)) + Streams = &llvm::debugstreams(); + if (const InputAction *IA = dyn_cast(A)) { // FIXME: It would be nice to not claim this here; maybe the old scheme of // just using Args was better? @@ -1169,14 +1191,14 @@ } if (CCCPrintBindings) { - llvm::errs() << "# \"" << T.getToolChain().getTripleString() << '"' + Streams->errs() << "# \"" << T.getToolChain().getTripleString() << '"' << " - \"" << T.getName() << "\", inputs: ["; for (unsigned i = 0, e = InputInfos.size(); i != e; ++i) { - llvm::errs() << InputInfos[i].getAsString(); + Streams->errs() << InputInfos[i].getAsString(); if (i + 1 != e) - llvm::errs() << ", "; + Streams->errs() << ", "; } - llvm::errs() << "], output: " << Result.getAsString() << "\n"; + Streams->errs() << "], output: " << Result.getAsString() << "\n"; } else { T.ConstructJob(C, *JA, Result, InputInfos, C.getArgsForToolChain(TC, BoundArch), LinkingOutput); Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp (revision 126559) +++ lib/Driver/Tools.cpp (working copy) @@ -488,7 +488,8 @@ } case llvm::Triple::Linux: { - if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUEABI) { + if (getToolChain().getTriple().getEnvironment() == + llvm::Triple::GNUEABI) { FloatABI = "softfp"; break; } @@ -1150,6 +1151,8 @@ Args.AddLastArg(CmdArgs, options::OPT_P); Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); + Args.AddLastArg(CmdArgs, options::OPT_output_diagnostics_as_debug_string); + // Special case debug options to only pass -g to clang. This is // wrong. Args.ClaimAllArgs(options::OPT_g_Group); @@ -1289,7 +1292,11 @@ } else { // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. - unsigned N = llvm::sys::Process::StandardErrColumns(); + unsigned N; + if (Args.hasArg(options::OPT_output_diagnostics_as_debug_string)) + N = 0; + else + N = llvm::sys::Process::StandardErrColumns(); CmdArgs.push_back(Args.MakeArgString(llvm::Twine(N))); } @@ -1801,6 +1808,8 @@ !IsOpt)) CmdArgs.push_back("-relax-all"); + Args.AddLastArg(CmdArgs, options::OPT_output_diagnostics_as_debug_string); + // FIXME: Add -force_cpusubtype_ALL support, once we have it. // FIXME: Add -g support, once we have it. @@ -1924,7 +1933,8 @@ } } - const char *GCCName = getToolChain().getDriver().getCCCGenericGCCName().c_str(); + const char *GCCName = + getToolChain().getDriver().getCCCGenericGCCName().c_str(); const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); Index: lib/Frontend/CompilerInstance.cpp =================================================================== --- lib/Frontend/CompilerInstance.cpp (revision 126559) +++ lib/Frontend/CompilerInstance.cpp (working copy) @@ -519,15 +519,12 @@ // High-Level Operations -bool CompilerInstance::ExecuteAction(FrontendAction &Act) { +bool CompilerInstance::ExecuteAction(FrontendAction &Act, + llvm::raw_ostream &OS) { assert(hasDiagnostics() && "Diagnostics engine is not initialized!"); assert(!getFrontendOpts().ShowHelp && "Client must handle '-help'!"); assert(!getFrontendOpts().ShowVersion && "Client must handle '-version'!"); - // FIXME: Take this as an argument, once all the APIs we used have moved to - // taking it as an input instead of hard-coding llvm::errs. - llvm::raw_ostream &OS = llvm::errs(); - // Create the target instance. setTarget(TargetInfo::CreateTargetInfo(getDiagnostics(), getTargetOpts())); if (!hasTarget()) Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp (revision 126559) +++ lib/Frontend/CompilerInvocation.cpp (working copy) @@ -273,6 +273,8 @@ Res.push_back("-fcolor-diagnostics"); if (Opts.VerifyDiagnostics) Res.push_back("-verify"); + if (Opts.OutputDiagnosticsAsDebugString) + Res.push_back("-output-diagnostics-as-debug-string"); if (Opts.ShowOptionNames) Res.push_back("-fdiagnostics-show-option"); if (Opts.ShowCategories == 1) @@ -1027,6 +1029,8 @@ Opts.ShowSourceRanges = Args.hasArg(OPT_fdiagnostics_print_source_range_info); Opts.ShowParseableFixits = Args.hasArg(OPT_fdiagnostics_parseable_fixits); Opts.VerifyDiagnostics = Args.hasArg(OPT_verify); + Opts.OutputDiagnosticsAsDebugString + = Args.hasArg(OPT_output_diagnostics_as_debug_string); Opts.ErrorLimit = Args.getLastArgIntValue(OPT_ferror_limit, 0, Diags); Opts.MacroBacktraceLimit = Args.getLastArgIntValue(OPT_fmacro_backtrace_limit, Index: lib/FrontendTool/ExecuteCompilerInvocation.cpp =================================================================== --- lib/FrontendTool/ExecuteCompilerInvocation.cpp (revision 126559) +++ lib/FrontendTool/ExecuteCompilerInvocation.cpp (working copy) @@ -99,18 +99,19 @@ return Act; } -bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { +bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang, + llvm::raw_output_streams &OutputStreams) { // Honor -help. if (Clang->getFrontendOpts().ShowHelp) { llvm::OwningPtr Opts(driver::createCC1OptTable()); - Opts->PrintHelp(llvm::outs(), "clang -cc1", + Opts->PrintHelp(OutputStreams.outs(), "clang -cc1", "LLVM 'Clang' Compiler: http://clang.llvm.org"); return 0; } // Honor -analyzer-checker-help. if (Clang->getAnalyzerOpts().ShowCheckerHelp) { - ento::printCheckerHelp(llvm::outs()); + ento::printCheckerHelp(OutputStreams.outs()); return 0; } @@ -151,7 +152,7 @@ // Create and execute the frontend action. llvm::OwningPtr Act(CreateFrontendAction(*Clang)); if (Act) { - Success = Clang->ExecuteAction(*Act); + Success = Clang->ExecuteAction(*Act, OutputStreams.errs()); if (Clang->getFrontendOpts().DisableFree) Act.take(); } Index: tools/driver/cc1_main.cpp =================================================================== --- tools/driver/cc1_main.cpp (revision 126559) +++ tools/driver/cc1_main.cpp (working copy) @@ -46,15 +46,26 @@ exit(1); } +static llvm::raw_output_streams &GetOutputStreams(const char **ArgBegin, + const char **ArgEnd) { + for (const char **Iter = ArgBegin; Iter != ArgEnd; ++Iter) { + if (llvm::StringRef(*Iter) == "-output-diagnostics-as-debug-string") + return llvm::debugstreams(); + } + return llvm::stdstreams(); +} + // FIXME: Define the need for this testing away. static int cc1_test(Diagnostic &Diags, const char **ArgBegin, const char **ArgEnd) { - using namespace clang::driver; + llvm::raw_output_streams &OS = GetOutputStreams(ArgBegin, ArgEnd); - llvm::errs() << "cc1 argv:"; + using namespace clang::driver; + + OS.errs() << "cc1 argv:"; for (const char **i = ArgBegin; i != ArgEnd; ++i) - llvm::errs() << " \"" << *i << '"'; - llvm::errs() << "\n"; + OS.errs() << " \"" << *i << '"'; + OS.errs() << "\n"; // Parse the arguments. OptTable *Opts = createCC1OptTable(); @@ -68,13 +79,13 @@ << Args->getArgString(MissingArgIndex) << MissingArgCount; // Dump the parsed arguments. - llvm::errs() << "cc1 parsed options:\n"; + OS.errs() << "cc1 parsed options:\n"; for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); it != ie; ++it) (*it)->dump(); // Create a compiler invocation. - llvm::errs() << "cc1 creating invocation.\n"; + OS.errs() << "cc1 creating invocation.\n"; CompilerInvocation Invocation; CompilerInvocation::CreateFromArgs(Invocation, ArgBegin, ArgEnd, Diags); @@ -84,12 +95,12 @@ // Dump the converted arguments. llvm::SmallVector Invocation2Args; - llvm::errs() << "invocation argv :"; + OS.errs() << "invocation argv :"; for (unsigned i = 0, e = InvocationArgs.size(); i != e; ++i) { Invocation2Args.push_back(InvocationArgs[i].c_str()); - llvm::errs() << " \"" << InvocationArgs[i] << '"'; + OS.errs() << " \"" << InvocationArgs[i] << '"'; } - llvm::errs() << "\n"; + OS.errs() << "\n"; // Convert those arguments to another invocation, and check that we got the // same thing. @@ -99,27 +110,29 @@ // FIXME: Implement CompilerInvocation comparison. if (true) { - //llvm::errs() << "warning: Invocations differ!\n"; + //OS.errs() << "warning: Invocations differ!\n"; std::vector Invocation2Args; Invocation2.toArgs(Invocation2Args); - llvm::errs() << "invocation2 argv:"; + OS.errs() << "invocation2 argv:"; for (unsigned i = 0, e = Invocation2Args.size(); i != e; ++i) - llvm::errs() << " \"" << Invocation2Args[i] << '"'; - llvm::errs() << "\n"; + OS.errs() << " \"" << Invocation2Args[i] << '"'; + OS.errs() << "\n"; } return 0; } int cc1_main(const char **ArgBegin, const char **ArgEnd, - const char *Argv0, void *MainAddr) { + const char *Argv0, void *MainAddr, bool IsRecursive) { + llvm::raw_output_streams &OS = GetOutputStreams(ArgBegin, ArgEnd); + llvm::OwningPtr Clang(new CompilerInstance()); llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); // Run clang -cc1 test. if (ArgBegin != ArgEnd && llvm::StringRef(ArgBegin[0]) == "-cc1test") { - Diagnostic Diags(DiagID, new TextDiagnosticPrinter(llvm::errs(), + Diagnostic Diags(DiagID, new TextDiagnosticPrinter(OS.errs(), DiagnosticOptions())); return cc1_test(Diags, ArgBegin + 1, ArgEnd); } @@ -143,7 +156,9 @@ CompilerInvocation::GetResourcesPath(Argv0, MainAddr); // Create the actual diagnostics engine. - Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast(ArgBegin)); + Clang->createDiagnostics(ArgEnd - ArgBegin, const_cast(ArgBegin), + new TextDiagnosticPrinter(OS.errs(), Clang->getDiagnosticOpts())); + if (!Clang->hasDiagnostics()) return 1; @@ -155,11 +170,11 @@ DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics()); // Execute the frontend actions. - bool Success = ExecuteCompilerInvocation(Clang.get()); + bool Success = ExecuteCompilerInvocation(Clang.get(), OS); // 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::TimerGroup::printAll(OS.errs()); // Our error handler depends on the Diagnostics object, which we're // potentially about to delete. Uninstall the handler now so that any @@ -176,7 +191,8 @@ // Managed static deconstruction. Useful for making things like // -time-passes usable. - llvm::llvm_shutdown(); + if (!IsRecursive) + llvm::llvm_shutdown(); return !Success; } Index: tools/driver/cc1as_main.cpp =================================================================== --- tools/driver/cc1as_main.cpp (revision 126559) +++ tools/driver/cc1as_main.cpp (working copy) @@ -329,8 +329,19 @@ exit(1); } +static raw_output_streams &GetOutputStreams(const char **ArgBegin, + const char **ArgEnd) { + for (const char **Iter = ArgBegin; Iter != ArgEnd; ++Iter) { + if (llvm::StringRef(*Iter) == "-output-diagnostics-as-debug-string") + return llvm::debugstreams(); + } + return llvm::stdstreams(); +} + int cc1as_main(const char **ArgBegin, const char **ArgEnd, - const char *Argv0, void *MainAddr) { + const char *Argv0, void *MainAddr, bool IsRecursive) { + + llvm::raw_output_streams &OS = GetOutputStreams(ArgBegin, ArgEnd); // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(); PrettyStackTraceProgram X(ArgEnd - ArgBegin, ArgBegin); @@ -345,7 +356,7 @@ // Construct our diagnostic client. TextDiagnosticPrinter *DiagClient - = new TextDiagnosticPrinter(errs(), DiagnosticOptions()); + = new TextDiagnosticPrinter(OS.errs(), DiagnosticOptions()); DiagClient->setPrefix("clang -cc1as"); llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); Diagnostic Diags(DiagID, DiagClient); @@ -362,7 +373,7 @@ // Honor -help. if (Asm.ShowHelp) { llvm::OwningPtr Opts(driver::createCC1AsOptTable()); - Opts->PrintHelp(llvm::outs(), "clang -cc1as", "Clang Integrated Assembler"); + Opts->PrintHelp(OS.outs(), "clang -cc1as", "Clang Integrated Assembler"); return 0; } @@ -394,7 +405,7 @@ // If any timers were active but haven't been destroyed yet, print their // results now. - TimerGroup::printAll(errs()); + TimerGroup::printAll(OS.errs()); return !Success; } Index: tools/driver/driver.cpp =================================================================== --- tools/driver/driver.cpp (revision 126559) +++ tools/driver/driver.cpp (working copy) @@ -54,6 +54,17 @@ return SavedStrings.insert(S).first->c_str(); } + +static llvm::raw_output_streams &GetOutputStreams(const char **ArgBegin, + const char **ArgEnd) { + for (const char **Iter = ArgBegin; Iter != ArgEnd; ++Iter) { + if (llvm::StringRef(*Iter) == "-output-diagnostics-as-debug-string") + return llvm::debugstreams(); + } + return llvm::stdstreams(); +} + + /// ApplyQAOverride - Apply a list of edits to the input argument lists. /// /// The input string is a space separate list of edits to perform, @@ -176,9 +187,9 @@ } extern int cc1_main(const char **ArgBegin, const char **ArgEnd, - const char *Argv0, void *MainAddr); + const char *Argv0, void *MainAddr, bool IsRecursive); extern int cc1as_main(const char **ArgBegin, const char **ArgEnd, - const char *Argv0, void *MainAddr); + const char *Argv0, void *MainAddr, bool IsRecursive); static void ExpandArgsFromBuf(const char *Arg, llvm::SmallVectorImpl &ArgVector, @@ -252,7 +263,11 @@ } } -int main(int argc_, const char **argv_) { +bool IsMainRecursive = false; +int cc_main(int argc_, const char **argv_) { + + llvm::raw_output_streams &OS = GetOutputStreams(argv_, argv_+argc_); + llvm::sys::PrintStackTraceOnErrorSignal(); llvm::PrettyStackTraceProgram X(argc_, argv_); @@ -267,13 +282,13 @@ if (Tool == "") return cc1_main(argv.data()+2, argv.data()+argv.size(), argv[0], - (void*) (intptr_t) GetExecutablePath); + (void*) (intptr_t) GetExecutablePath, IsMainRecursive); if (Tool == "as") return cc1as_main(argv.data()+2, argv.data()+argv.size(), argv[0], - (void*) (intptr_t) GetExecutablePath); + (void*) (intptr_t) GetExecutablePath, IsMainRecursive); // Reject unknown tools. - llvm::errs() << "error: unknown integrated tool '" << Tool << "'\n"; + OS.errs() << "error: unknown integrated tool '" << Tool << "'\n"; return 1; } @@ -287,8 +302,15 @@ llvm::sys::Path Path = GetExecutablePath(argv[0], CanonicalPrefixes); + if (IsMainRecursive) { + OS.errs() << "error: recursive cc_main without known integrated tool'\n"; + return 1; + } + IsMainRecursive = true; + CompilationThisProgramScope ThisProgramScope(&cc_main, Path.c_str()); + TextDiagnosticPrinter *DiagClient - = new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + = new TextDiagnosticPrinter(OS.errs(), DiagnosticOptions()); DiagClient->setPrefix(llvm::sys::path::stem(Path.str())); llvm::IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); Diagnostic Diags(DiagID, DiagClient); @@ -386,9 +408,14 @@ // 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::TimerGroup::printAll(OS.errs()); llvm::llvm_shutdown(); + IsMainRecursive = false; return Res; } + +int main(int argc_, const char **argv_) { + return cc_main(argc_, argv_); +} Index: unittests/Frontend/FrontendActionTest.cpp =================================================================== --- unittests/Frontend/FrontendActionTest.cpp (revision 126559) +++ unittests/Frontend/FrontendActionTest.cpp (working copy) @@ -64,7 +64,7 @@ compiler.createDiagnostics(0, NULL); TestASTFrontendAction test_action; - ASSERT_TRUE(compiler.ExecuteAction(test_action)); + ASSERT_TRUE(compiler.ExecuteAction(test_action, llvm::errs())); ASSERT_EQ(3U, test_action.decl_names.size()); EXPECT_EQ("__builtin_va_list", test_action.decl_names[0]); EXPECT_EQ("main", test_action.decl_names[1]);