LCOV - code coverage report
Current view: top level - lib/Support - GraphWriter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 12 152 7.9 %
Date: 2017-09-14 15:23:50 Functions: 3 8 37.5 %
Legend: Lines: hit not hit

          Line data    Source code
       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/ADT/SmallString.h"
      16             : #include "llvm/ADT/SmallVector.h"
      17             : #include "llvm/ADT/StringRef.h"
      18             : #include "llvm/Config/config.h"
      19             : #include "llvm/Support/CommandLine.h"
      20             : #include "llvm/Support/Compiler.h"
      21             : #include "llvm/Support/ErrorHandling.h"
      22             : #include "llvm/Support/ErrorOr.h"
      23             : #include "llvm/Support/FileSystem.h"
      24             : #include "llvm/Support/Program.h"
      25             : #include "llvm/Support/raw_ostream.h"
      26             : #include <cassert>
      27             : #include <system_error>
      28             : #include <string>
      29             : #include <vector>
      30             : 
      31             : using namespace llvm;
      32             : 
      33       72306 : static cl::opt<bool> ViewBackground("view-background", cl::Hidden,
      34      144612 :   cl::desc("Execute graph viewer in the background. Creates tmp file litter."));
      35             : 
      36          30 : std::string llvm::DOT::EscapeString(const std::string &Label) {
      37          30 :   std::string Str(Label);
      38        2720 :   for (unsigned i = 0; i != Str.length(); ++i)
      39        5380 :   switch (Str[i]) {
      40           0 :     case '\n':
      41           0 :       Str.insert(Str.begin()+i, '\\');  // Escape character...
      42           0 :       ++i;
      43           0 :       Str[i] = 'n';
      44           0 :       break;
      45           0 :     case '\t':
      46           0 :       Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
      47           0 :       ++i;
      48           0 :       Str[i] = ' ';
      49           0 :       break;
      50          66 :     case '\\':
      51          66 :       if (i+1 != Str.length())
      52         198 :         switch (Str[i+1]) {
      53         132 :           case 'l': continue; // don't disturb \l
      54           0 :           case '|': case '{': case '}':
      55           0 :             Str.erase(Str.begin()+i); continue;
      56             :           default: break;
      57             :         }
      58             :         LLVM_FALLTHROUGH;
      59             :     case '{': case '}':
      60             :     case '<': case '>':
      61             :     case '|': case '"':
      62           0 :       Str.insert(Str.begin()+i, '\\');  // Escape character...
      63           0 :       ++i;  // don't infinite loop
      64           0 :       break;
      65             :   }
      66          30 :   return Str;
      67             : }
      68             : 
      69             : /// \brief Get a color string for this node number. Simply round-robin selects
      70             : /// from a reasonable number of colors.
      71           0 : StringRef llvm::DOT::getColorString(unsigned ColorNumber) {
      72             :   static const int NumColors = 20;
      73             :   static const char* Colors[NumColors] = {
      74             :     "aaaaaa", "aa0000", "00aa00", "aa5500", "0055ff", "aa00aa", "00aaaa",
      75             :     "555555", "ff5555", "55ff55", "ffff55", "5555ff", "ff55ff", "55ffff",
      76             :     "ffaaaa", "aaffaa", "ffffaa", "aaaaff", "ffaaff", "aaffff"};
      77           0 :   return Colors[ColorNumber % NumColors];
      78             : }
      79             : 
      80           0 : std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
      81           0 :   FD = -1;
      82           0 :   SmallString<128> Filename;
      83           0 :   std::error_code EC = sys::fs::createTemporaryFile(Name, "dot", FD, Filename);
      84           0 :   if (EC) {
      85           0 :     errs() << "Error: " << EC.message() << "\n";
      86           0 :     return "";
      87             :   }
      88             : 
      89           0 :   errs() << "Writing '" << Filename << "'... ";
      90           0 :   return Filename.str();
      91             : }
      92             : 
      93             : // Execute the graph viewer. Return true if there were errors.
      94           0 : static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args,
      95             :                             StringRef Filename, bool wait,
      96             :                             std::string &ErrMsg) {
      97             :   assert(args.back() == nullptr);
      98           0 :   if (wait) {
      99           0 :     if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, {}, 0, 0,
     100           0 :                             &ErrMsg)) {
     101           0 :       errs() << "Error: " << ErrMsg << "\n";
     102           0 :       return true;
     103             :     }
     104           0 :     sys::fs::remove(Filename);
     105           0 :     errs() << " done. \n";
     106             :   } else {
     107           0 :     sys::ExecuteNoWait(ExecPath, args.data(), nullptr, {}, 0, &ErrMsg);
     108           0 :     errs() << "Remember to erase graph file: " << Filename << "\n";
     109             :   }
     110             :   return false;
     111             : }
     112             : 
     113             : namespace {
     114             : 
     115           0 : struct GraphSession {
     116             :   std::string LogBuffer;
     117             : 
     118           0 :   bool TryFindProgram(StringRef Names, std::string &ProgramPath) {
     119           0 :     raw_string_ostream Log(LogBuffer);
     120           0 :     SmallVector<StringRef, 8> parts;
     121           0 :     Names.split(parts, '|');
     122           0 :     for (auto Name : parts) {
     123           0 :       if (ErrorOr<std::string> P = sys::findProgramByName(Name)) {
     124           0 :         ProgramPath = *P;
     125           0 :         return true;
     126             :       }
     127           0 :       Log << "  Tried '" << Name << "'\n";
     128             :     }
     129           0 :     return false;
     130             :   }
     131             : };
     132             : 
     133             : } // end anonymous namespace
     134             : 
     135             : static const char *getProgramName(GraphProgram::Name program) {
     136           0 :   switch (program) {
     137             :   case GraphProgram::DOT:
     138             :     return "dot";
     139           0 :   case GraphProgram::FDP:
     140             :     return "fdp";
     141           0 :   case GraphProgram::NEATO:
     142             :     return "neato";
     143           0 :   case GraphProgram::TWOPI:
     144             :     return "twopi";
     145           0 :   case GraphProgram::CIRCO:
     146             :     return "circo";
     147             :   }
     148           0 :   llvm_unreachable("bad kind");
     149             : }
     150             : 
     151           0 : bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
     152             :                         GraphProgram::Name program) {
     153           0 :   std::string Filename = FilenameRef;
     154           0 :   std::string ErrMsg;
     155           0 :   std::string ViewerPath;
     156           0 :   GraphSession S;
     157             : 
     158             : #ifdef __APPLE__
     159             :   wait &= !ViewBackground;
     160             :   if (S.TryFindProgram("open", ViewerPath)) {
     161             :     std::vector<const char *> args;
     162             :     args.push_back(ViewerPath.c_str());
     163             :     if (wait)
     164             :       args.push_back("-W");
     165             :     args.push_back(Filename.c_str());
     166             :     args.push_back(nullptr);
     167             :     errs() << "Trying 'open' program... ";
     168             :     if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
     169             :       return false;
     170             :   }
     171             : #endif
     172           0 :   if (S.TryFindProgram("xdg-open", ViewerPath)) {
     173           0 :     std::vector<const char *> args;
     174           0 :     args.push_back(ViewerPath.c_str());
     175           0 :     args.push_back(Filename.c_str());
     176           0 :     args.push_back(nullptr);
     177           0 :     errs() << "Trying 'xdg-open' program... ";
     178           0 :     if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
     179           0 :       return false;
     180             :   }
     181             : 
     182             :   // Graphviz
     183           0 :   if (S.TryFindProgram("Graphviz", ViewerPath)) {
     184           0 :     std::vector<const char *> args;
     185           0 :     args.push_back(ViewerPath.c_str());
     186           0 :     args.push_back(Filename.c_str());
     187           0 :     args.push_back(nullptr);
     188             : 
     189           0 :     errs() << "Running 'Graphviz' program... ";
     190           0 :     return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
     191             :   }
     192             : 
     193             :   // xdot
     194           0 :   if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) {
     195           0 :     std::vector<const char *> args;
     196           0 :     args.push_back(ViewerPath.c_str());
     197           0 :     args.push_back(Filename.c_str());
     198             : 
     199           0 :     args.push_back("-f");
     200           0 :     args.push_back(getProgramName(program));
     201             : 
     202           0 :     args.push_back(nullptr);
     203             : 
     204           0 :     errs() << "Running 'xdot.py' program... ";
     205           0 :     return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
     206             :   }
     207             : 
     208             :   enum ViewerKind {
     209             :     VK_None,
     210             :     VK_OSXOpen,
     211             :     VK_XDGOpen,
     212             :     VK_Ghostview,
     213             :     VK_CmdStart
     214             :   };
     215           0 :   ViewerKind Viewer = VK_None;
     216             : #ifdef __APPLE__
     217             :   if (!Viewer && S.TryFindProgram("open", ViewerPath))
     218             :     Viewer = VK_OSXOpen;
     219             : #endif
     220           0 :   if (!Viewer && S.TryFindProgram("gv", ViewerPath))
     221           0 :     Viewer = VK_Ghostview;
     222           0 :   if (!Viewer && S.TryFindProgram("xdg-open", ViewerPath))
     223             :     Viewer = VK_XDGOpen;
     224             : #ifdef LLVM_ON_WIN32
     225             :   if (!Viewer && S.TryFindProgram("cmd", ViewerPath)) {
     226             :     Viewer = VK_CmdStart;
     227             :   }
     228             : #endif
     229             : 
     230             :   // PostScript or PDF graph generator + PostScript/PDF viewer
     231           0 :   std::string GeneratorPath;
     232           0 :   if (Viewer &&
     233           0 :       (S.TryFindProgram(getProgramName(program), GeneratorPath) ||
     234           0 :        S.TryFindProgram("dot|fdp|neato|twopi|circo", GeneratorPath))) {
     235             :     std::string OutputFilename =
     236           0 :         Filename + (Viewer == VK_CmdStart ? ".pdf" : ".ps");
     237             : 
     238           0 :     std::vector<const char *> args;
     239           0 :     args.push_back(GeneratorPath.c_str());
     240             :     if (Viewer == VK_CmdStart)
     241             :       args.push_back("-Tpdf");
     242             :     else
     243           0 :       args.push_back("-Tps");
     244           0 :     args.push_back("-Nfontname=Courier");
     245           0 :     args.push_back("-Gsize=7.5,10");
     246           0 :     args.push_back(Filename.c_str());
     247           0 :     args.push_back("-o");
     248           0 :     args.push_back(OutputFilename.c_str());
     249           0 :     args.push_back(nullptr);
     250             : 
     251           0 :     errs() << "Running '" << GeneratorPath << "' program... ";
     252             : 
     253           0 :     if (ExecGraphViewer(GeneratorPath, args, Filename, true, ErrMsg))
     254             :       return true;
     255             : 
     256             :     // The lifetime of StartArg must include the call of ExecGraphViewer
     257             :     // because the args are passed as vector of char*.
     258           0 :     std::string StartArg;
     259             : 
     260           0 :     args.clear();
     261           0 :     args.push_back(ViewerPath.c_str());
     262           0 :     switch (Viewer) {
     263           0 :     case VK_OSXOpen:
     264           0 :       args.push_back("-W");
     265           0 :       args.push_back(OutputFilename.c_str());
     266           0 :       break;
     267           0 :     case VK_XDGOpen:
     268           0 :       wait = false;
     269           0 :       args.push_back(OutputFilename.c_str());
     270           0 :       break;
     271           0 :     case VK_Ghostview:
     272           0 :       args.push_back("--spartan");
     273           0 :       args.push_back(OutputFilename.c_str());
     274           0 :       break;
     275           0 :     case VK_CmdStart:
     276           0 :       args.push_back("/S");
     277           0 :       args.push_back("/C");
     278           0 :       StartArg =
     279           0 :           (StringRef("start ") + (wait ? "/WAIT " : "") + OutputFilename).str();
     280           0 :       args.push_back(StartArg.c_str());
     281           0 :       break;
     282           0 :     case VK_None:
     283           0 :       llvm_unreachable("Invalid viewer");
     284             :     }
     285           0 :     args.push_back(nullptr);
     286             : 
     287           0 :     ErrMsg.clear();
     288           0 :     return ExecGraphViewer(ViewerPath, args, OutputFilename, wait, ErrMsg);
     289             :   }
     290             : 
     291             :   // dotty
     292           0 :   if (S.TryFindProgram("dotty", ViewerPath)) {
     293           0 :     std::vector<const char *> args;
     294           0 :     args.push_back(ViewerPath.c_str());
     295           0 :     args.push_back(Filename.c_str());
     296           0 :     args.push_back(nullptr);
     297             : 
     298             : // Dotty spawns another app and doesn't wait until it returns
     299             : #ifdef LLVM_ON_WIN32
     300             :     wait = false;
     301             : #endif
     302           0 :     errs() << "Running 'dotty' program... ";
     303           0 :     return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
     304             :   }
     305             : 
     306           0 :   errs() << "Error: Couldn't find a usable graph viewer program:\n";
     307           0 :   errs() << S.LogBuffer << "\n";
     308           0 :   return true;
     309      216918 : }

Generated by: LCOV version 1.13