GraphWriter.cpp revision 675e0ac0bfd6fb78423d9fbee9f50c1dec62c111
1//===-- GraphWriter.cpp - Implements GraphWriter support routines ---------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements misc. GraphWriter support routines.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/Support/GraphWriter.h"
15#include "llvm/Config/config.h"
16#include "llvm/Support/CommandLine.h"
17#include "llvm/Support/FileSystem.h"
18#include "llvm/Support/Path.h"
19#include "llvm/Support/PathV1.h"
20#include "llvm/Support/Program.h"
21using namespace llvm;
22
23static cl::opt<bool> ViewBackground("view-background", cl::Hidden,
24  cl::desc("Execute graph viewer in the background. Creates tmp file litter."));
25
26std::string llvm::DOT::EscapeString(const std::string &Label) {
27  std::string Str(Label);
28  for (unsigned i = 0; i != Str.length(); ++i)
29  switch (Str[i]) {
30    case '\n':
31      Str.insert(Str.begin()+i, '\\');  // Escape character...
32      ++i;
33      Str[i] = 'n';
34      break;
35    case '\t':
36      Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
37      ++i;
38      Str[i] = ' ';
39      break;
40    case '\\':
41      if (i+1 != Str.length())
42        switch (Str[i+1]) {
43          case 'l': continue; // don't disturb \l
44          case '|': case '{': case '}':
45            Str.erase(Str.begin()+i); continue;
46          default: break;
47        }
48    case '{': case '}':
49    case '<': case '>':
50    case '|': case '"':
51      Str.insert(Str.begin()+i, '\\');  // Escape character...
52      ++i;  // don't infinite loop
53      break;
54  }
55  return Str;
56}
57
58/// \brief Get a color string for this node number. Simply round-robin selects
59/// from a reasonable number of colors.
60StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
61  static const int NumColors = 20;
62  static const char* Colors[NumColors] = {
63    "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa",
64    "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff",
65    "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"};
66  return Colors[ColorNumber % NumColors];
67}
68
69std::string llvm::createGraphFilename(const Twine &Name) {
70  std::string ErrMsg;
71  sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg);
72  if (Filename.isEmpty()) {
73    errs() << "Error: " << ErrMsg << "\n";
74    return "";
75  }
76  Filename.appendComponent((Name + ".dot").str());
77  if (Filename.makeUnique(true,&ErrMsg)) {
78    errs() << "Error: " << ErrMsg << "\n";
79    return "";
80  }
81  return Filename.str();
82}
83
84// Execute the graph viewer. Return true if successful.
85static bool LLVM_ATTRIBUTE_UNUSED
86ExecGraphViewer(StringRef ExecPath, std::vector<const char*> &args,
87                StringRef Filename, bool wait, std::string &ErrMsg) {
88  if (wait) {
89    if (sys::ExecuteAndWait(ExecPath, &args[0],0,0,0,0,&ErrMsg)) {
90      errs() << "Error: " << ErrMsg << "\n";
91      return false;
92    }
93    bool Existed;
94    sys::fs::remove(Filename, Existed);
95    errs() << " done. \n";
96  }
97  else {
98    sys::ExecuteNoWait(ExecPath, &args[0],0,0,0,&ErrMsg);
99    errs() << "Remember to erase graph file: " << Filename.str() << "\n";
100  }
101  return true;
102}
103
104void llvm::DisplayGraph(StringRef FilenameRef, bool wait,
105                        GraphProgram::Name program) {
106  std::string Filename = FilenameRef;
107  wait &= !ViewBackground;
108  std::string ErrMsg;
109#if HAVE_GRAPHVIZ
110  std::string Graphviz(LLVM_PATH_GRAPHVIZ);
111
112  std::vector<const char*> args;
113  args.push_back(Graphviz.c_str());
114  args.push_back(Filename.c_str());
115  args.push_back(0);
116
117  errs() << "Running 'Graphviz' program... ";
118  if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg))
119    return;
120
121#elif HAVE_XDOT_PY
122  std::vector<const char*> args;
123  args.push_back(LLVM_PATH_XDOT_PY);
124  args.push_back(Filename.c_str());
125
126  switch (program) {
127  case GraphProgram::DOT:   args.push_back("-f"); args.push_back("dot"); break;
128  case GraphProgram::FDP:   args.push_back("-f"); args.push_back("fdp"); break;
129  case GraphProgram::NEATO: args.push_back("-f"); args.push_back("neato");break;
130  case GraphProgram::TWOPI: args.push_back("-f"); args.push_back("twopi");break;
131  case GraphProgram::CIRCO: args.push_back("-f"); args.push_back("circo");break;
132  }
133
134  args.push_back(0);
135
136  errs() << "Running 'xdot.py' program... ";
137  if (!ExecGraphViewer(LLVM_PATH_XDOT_PY, args, Filename, wait, ErrMsg))
138    return;
139
140#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \
141                   HAVE_TWOPI || HAVE_CIRCO))
142  sys::Path PSFilename = sys::Path(Filename);
143  PSFilename.appendSuffix("ps");
144
145  std::string prog;
146
147  // Set default grapher
148#if HAVE_CIRCO
149  prog = LLVM_PATH_CIRCO;
150#endif
151#if HAVE_TWOPI
152  prog = LLVM_PATH_TWOPI;
153#endif
154#if HAVE_NEATO
155  prog = LLVM_PATH_NEATO;
156#endif
157#if HAVE_FDP
158  prog = LLVM_PATH_FDP;
159#endif
160#if HAVE_DOT
161  prog = LLVM_PATH_DOT;
162#endif
163
164  // Find which program the user wants
165#if HAVE_DOT
166  if (program == GraphProgram::DOT)
167    prog = LLVM_PATH_DOT;
168#endif
169#if (HAVE_FDP)
170  if (program == GraphProgram::FDP)
171    prog = LLVM_PATH_FDP;
172#endif
173#if (HAVE_NEATO)
174  if (program == GraphProgram::NEATO)
175    prog = LLVM_PATH_NEATO;
176#endif
177#if (HAVE_TWOPI)
178  if (program == GraphProgram::TWOPI)
179    prog = LLVM_PATH_TWOPI;
180#endif
181#if (HAVE_CIRCO)
182  if (program == GraphProgram::CIRCO)
183    prog = LLVM_PATH_CIRCO;
184#endif
185
186  std::vector<const char*> args;
187  args.push_back(prog.c_str());
188  args.push_back("-Tps");
189  args.push_back("-Nfontname=Courier");
190  args.push_back("-Gsize=7.5,10");
191  args.push_back(Filename.c_str());
192  args.push_back("-o");
193  args.push_back(PSFilename.c_str());
194  args.push_back(0);
195
196  errs() << "Running '" << prog << "' program... ";
197
198  if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg))
199    return;
200
201  std::string gv(LLVM_PATH_GV);
202  args.clear();
203  args.push_back(gv.c_str());
204  args.push_back(PSFilename.c_str());
205  args.push_back("--spartan");
206  args.push_back(0);
207
208  ErrMsg.clear();
209  if (!ExecGraphViewer(gv, args, PSFilename.str(), wait, ErrMsg))
210    return;
211
212#elif HAVE_DOTTY
213  std::string dotty(LLVM_PATH_DOTTY);
214
215  std::vector<const char*> args;
216  args.push_back(dotty.c_str());
217  args.push_back(Filename.c_str());
218  args.push_back(0);
219
220// Dotty spawns another app and doesn't wait until it returns
221#if defined (__MINGW32__) || defined (_WINDOWS)
222  wait = false;
223#endif
224  errs() << "Running 'dotty' program... ";
225  if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg))
226    return;
227#endif
228}
229