Query CompilationDatabase right before running each compilation.

Summary:
Query CompilationDatabase right before running each compilation. This allows
supporting compilation databases that change external state required for
successful compilation.

Reviewers: klimek, djasper

Reviewed By: djasper

Subscribers: klimek, cfe-commits

Differential Revision: http://reviews.llvm.org/D5086

llvm-svn: 216620
This commit is contained in:
Alexander Kornienko
2014-08-27 21:36:39 +00:00
parent dd96db2c03
commit 9a45fac6f7
2 changed files with 46 additions and 51 deletions

View File

@@ -273,28 +273,10 @@ bool FrontendActionFactory::runInvocation(CompilerInvocation *Invocation,
ClangTool::ClangTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
: Files(new FileManager(FileSystemOptions())), DiagConsumer(nullptr) {
: Compilations(Compilations), SourcePaths(SourcePaths),
Files(new FileManager(FileSystemOptions())), DiagConsumer(nullptr) {
ArgsAdjusters.push_back(new ClangStripOutputAdjuster());
ArgsAdjusters.push_back(new ClangSyntaxOnlyAdjuster());
for (const auto &SourcePath : SourcePaths) {
std::string File(getAbsolutePath(SourcePath));
std::vector<CompileCommand> CompileCommandsForFile =
Compilations.getCompileCommands(File);
if (!CompileCommandsForFile.empty()) {
for (CompileCommand &CompileCommand : CompileCommandsForFile) {
CompileCommands.push_back(
std::make_pair(File, std::move(CompileCommand)));
}
} else {
// FIXME: There are two use cases here: doing a fuzzy
// "find . -name '*.cc' |xargs tool" match, where as a user I don't care
// about the .cc files that were not found, and the use case where I
// specify all files I want to run over explicitly, where this should
// be an error. We'll want to add an option for this.
llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
}
}
}
void ClangTool::setDiagnosticConsumer(DiagnosticConsumer *D) {
@@ -333,36 +315,49 @@ int ClangTool::run(ToolAction *Action) {
llvm::sys::fs::getMainExecutable("clang_tool", &StaticSymbol);
bool ProcessingFailed = false;
for (const auto &Command : CompileCommands) {
// FIXME: chdir is thread hostile; on the other hand, creating the same
// behavior as chdir is complex: chdir resolves the path once, thus
// guaranteeing that all subsequent relative path operations work
// on the same path the original chdir resulted in. This makes a difference
// for example on network filesystems, where symlinks might be switched
// during runtime of the tool. Fixing this depends on having a file system
// abstraction that allows openat() style interactions.
if (chdir(Command.second.Directory.c_str()))
llvm::report_fatal_error("Cannot chdir into \"" +
Twine(Command.second.Directory) + "\n!");
std::vector<std::string> CommandLine = Command.second.CommandLine;
for (ArgumentsAdjuster *Adjuster : ArgsAdjusters)
CommandLine = Adjuster->Adjust(CommandLine);
assert(!CommandLine.empty());
CommandLine[0] = MainExecutable;
// FIXME: We need a callback mechanism for the tool writer to output a
// customized message for each file.
DEBUG({
llvm::dbgs() << "Processing: " << Command.first << ".\n";
});
ToolInvocation Invocation(std::move(CommandLine), Action, Files.get());
Invocation.setDiagnosticConsumer(DiagConsumer);
for (const auto &MappedFile : MappedFileContents) {
Invocation.mapVirtualFile(MappedFile.first, MappedFile.second);
for (const auto &SourcePath : SourcePaths) {
std::string File(getAbsolutePath(SourcePath));
std::vector<CompileCommand> CompileCommandsForFile =
Compilations.getCompileCommands(File);
if (CompileCommandsForFile.empty()) {
// FIXME: There are two use cases here: doing a fuzzy
// "find . -name '*.cc' |xargs tool" match, where as a user I don't care
// about the .cc files that were not found, and the use case where I
// specify all files I want to run over explicitly, where this should
// be an error. We'll want to add an option for this.
llvm::errs() << "Skipping " << File << ". Compile command not found.\n";
continue;
}
if (!Invocation.run()) {
// FIXME: Diagnostics should be used instead.
llvm::errs() << "Error while processing " << Command.first << ".\n";
ProcessingFailed = true;
for (CompileCommand &CompileCommand : CompileCommandsForFile) {
// FIXME: chdir is thread hostile; on the other hand, creating the same
// behavior as chdir is complex: chdir resolves the path once, thus
// guaranteeing that all subsequent relative path operations work
// on the same path the original chdir resulted in. This makes a
// difference for example on network filesystems, where symlinks might be
// switched during runtime of the tool. Fixing this depends on having a
// file system abstraction that allows openat() style interactions.
if (chdir(CompileCommand.Directory.c_str()))
llvm::report_fatal_error("Cannot chdir into \"" +
Twine(CompileCommand.Directory) + "\n!");
std::vector<std::string> CommandLine = CompileCommand.CommandLine;
for (ArgumentsAdjuster *Adjuster : ArgsAdjusters)
CommandLine = Adjuster->Adjust(CommandLine);
assert(!CommandLine.empty());
CommandLine[0] = MainExecutable;
// FIXME: We need a callback mechanism for the tool writer to output a
// customized message for each file.
DEBUG({ llvm::dbgs() << "Processing: " << File << ".\n"; });
ToolInvocation Invocation(std::move(CommandLine), Action, Files.get());
Invocation.setDiagnosticConsumer(DiagConsumer);
for (const auto &MappedFile : MappedFileContents) {
Invocation.mapVirtualFile(MappedFile.first, MappedFile.second);
}
if (!Invocation.run()) {
// FIXME: Diagnostics should be used instead.
llvm::errs() << "Error while processing " << File << ".\n";
ProcessingFailed = true;
}
}
}
return ProcessingFailed ? 1 : 0;