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));
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
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;
}