2012-02-02 08:54:52 +08:00
|
|
|
//===--- DependencyGraph.cpp - Generate dependency file -------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2012-02-03 07:45:13 +08:00
|
|
|
// This code generates a header dependency graph in DOT format, for use
|
|
|
|
// with, e.g., GraphViz.
|
2012-02-02 08:54:52 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/Frontend/Utils.h"
|
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "clang/Frontend/FrontendDiagnostic.h"
|
|
|
|
#include "clang/Lex/PPCallbacks.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
|
|
|
#include "llvm/ADT/SetVector.h"
|
|
|
|
#include "llvm/Support/GraphWriter.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-02-02 08:54:52 +08:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
namespace DOT = llvm::DOT;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class DependencyGraphCallback : public PPCallbacks {
|
|
|
|
const Preprocessor *PP;
|
|
|
|
std::string OutputFile;
|
|
|
|
std::string SysRoot;
|
|
|
|
llvm::SetVector<const FileEntry *> AllFiles;
|
2013-01-13 03:30:44 +08:00
|
|
|
typedef llvm::DenseMap<const FileEntry *,
|
|
|
|
SmallVector<const FileEntry *, 2> > DependencyMap;
|
2012-02-02 08:54:52 +08:00
|
|
|
|
|
|
|
DependencyMap Dependencies;
|
|
|
|
|
|
|
|
private:
|
2013-01-13 03:30:44 +08:00
|
|
|
raw_ostream &writeNodeReference(raw_ostream &OS,
|
|
|
|
const FileEntry *Node);
|
2012-02-02 08:54:52 +08:00
|
|
|
void OutputGraphFile();
|
|
|
|
|
|
|
|
public:
|
|
|
|
DependencyGraphCallback(const Preprocessor *_PP, StringRef OutputFile,
|
|
|
|
StringRef SysRoot)
|
|
|
|
: PP(_PP), OutputFile(OutputFile.str()), SysRoot(SysRoot.str()) { }
|
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok,
|
|
|
|
StringRef FileName, bool IsAngled,
|
|
|
|
CharSourceRange FilenameRange, const FileEntry *File,
|
|
|
|
StringRef SearchPath, StringRef RelativePath,
|
|
|
|
const Module *Imported) override;
|
2012-02-02 08:54:52 +08:00
|
|
|
|
2014-03-13 14:07:04 +08:00
|
|
|
void EndOfMainFile() override {
|
2012-02-02 08:54:52 +08:00
|
|
|
OutputGraphFile();
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
void clang::AttachDependencyGraphGen(Preprocessor &PP, StringRef OutputFile,
|
|
|
|
StringRef SysRoot) {
|
2014-09-10 12:53:53 +08:00
|
|
|
PP.addPPCallbacks(llvm::make_unique<DependencyGraphCallback>(&PP, OutputFile,
|
|
|
|
SysRoot));
|
2012-02-02 08:54:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc,
|
|
|
|
const Token &IncludeTok,
|
|
|
|
StringRef FileName,
|
|
|
|
bool IsAngled,
|
2012-09-27 09:42:07 +08:00
|
|
|
CharSourceRange FilenameRange,
|
2012-02-02 08:54:52 +08:00
|
|
|
const FileEntry *File,
|
|
|
|
StringRef SearchPath,
|
2012-09-29 09:06:10 +08:00
|
|
|
StringRef RelativePath,
|
|
|
|
const Module *Imported) {
|
2012-02-02 08:54:52 +08:00
|
|
|
if (!File)
|
|
|
|
return;
|
|
|
|
|
|
|
|
SourceManager &SM = PP->getSourceManager();
|
|
|
|
const FileEntry *FromFile
|
|
|
|
= SM.getFileEntryForID(SM.getFileID(SM.getExpansionLoc(HashLoc)));
|
2014-05-22 12:46:25 +08:00
|
|
|
if (!FromFile)
|
2012-02-02 08:54:52 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
Dependencies[FromFile].push_back(File);
|
|
|
|
|
|
|
|
AllFiles.insert(File);
|
|
|
|
AllFiles.insert(FromFile);
|
|
|
|
}
|
|
|
|
|
2013-01-13 03:30:44 +08:00
|
|
|
raw_ostream &
|
|
|
|
DependencyGraphCallback::writeNodeReference(raw_ostream &OS,
|
2012-02-02 08:54:52 +08:00
|
|
|
const FileEntry *Node) {
|
|
|
|
OS << "header_" << Node->getUID();
|
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DependencyGraphCallback::OutputGraphFile() {
|
2014-08-26 02:17:04 +08:00
|
|
|
std::error_code EC;
|
|
|
|
llvm::raw_fd_ostream OS(OutputFile, EC, llvm::sys::fs::F_Text);
|
|
|
|
if (EC) {
|
|
|
|
PP->getDiagnostics().Report(diag::err_fe_error_opening) << OutputFile
|
|
|
|
<< EC.message();
|
2012-02-02 08:54:52 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
OS << "digraph \"dependencies\" {\n";
|
|
|
|
|
|
|
|
// Write the nodes
|
|
|
|
for (unsigned I = 0, N = AllFiles.size(); I != N; ++I) {
|
|
|
|
// Write the node itself.
|
|
|
|
OS.indent(2);
|
|
|
|
writeNodeReference(OS, AllFiles[I]);
|
|
|
|
OS << " [ shape=\"box\", label=\"";
|
|
|
|
StringRef FileName = AllFiles[I]->getName();
|
|
|
|
if (FileName.startswith(SysRoot))
|
|
|
|
FileName = FileName.substr(SysRoot.size());
|
|
|
|
|
|
|
|
OS << DOT::EscapeString(FileName)
|
|
|
|
<< "\"];\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the edges
|
|
|
|
for (DependencyMap::iterator F = Dependencies.begin(),
|
|
|
|
FEnd = Dependencies.end();
|
|
|
|
F != FEnd; ++F) {
|
|
|
|
for (unsigned I = 0, N = F->second.size(); I != N; ++I) {
|
|
|
|
OS.indent(2);
|
|
|
|
writeNodeReference(OS, F->first);
|
|
|
|
OS << " -> ";
|
|
|
|
writeNodeReference(OS, F->second[I]);
|
|
|
|
OS << ";\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
OS << "}\n";
|
|
|
|
}
|
|
|
|
|