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