LCOV - code coverage report
Current view: top level - lib/Support - GraphWriter.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 7 109 6.4 %
Date: 2018-10-20 13:21:21 Functions: 1 6 16.7 %
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             : static cl::opt<bool> ViewBackground("view-background", cl::Hidden,
      34             :   cl::desc("Execute graph viewer in the background. Creates tmp file litter."));
      35             : 
      36          37 : std::string llvm::DOT::EscapeString(const std::string &Label) {
      37             :   std::string Str(Label);
      38        2830 :   for (unsigned i = 0; i != Str.length(); ++i)
      39        2793 :   switch (Str[i]) {
      40           0 :     case '\n':
      41             :       Str.insert(Str.begin()+i, '\\');  // Escape character...
      42           0 :       ++i;
      43           0 :       Str[i] = 'n';
      44           0 :       break;
      45           0 :     case '\t':
      46             :       Str.insert(Str.begin()+i, ' ');  // Convert to two spaces
      47           0 :       ++i;
      48           0 :       Str[i] = ' ';
      49           0 :       break;
      50          65 :     case '\\':
      51          65 :       if (i+1 != Str.length())
      52          65 :         switch (Str[i+1]) {
      53             :           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             :       Str.insert(Str.begin()+i, '\\');  // Escape character...
      63           0 :       ++i;  // don't infinite loop
      64           0 :       break;
      65             :   }
      66          37 :   return Str;
      67             : }
      68             : 
      69             : /// 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             :   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             :   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<StringRef> &args,
      95             :                             StringRef Filename, bool wait,
      96             :                             std::string &ErrMsg) {
      97           0 :   if (wait) {
      98           0 :     if (sys::ExecuteAndWait(ExecPath, args, None, {}, 0, 0, &ErrMsg)) {
      99           0 :       errs() << "Error: " << ErrMsg << "\n";
     100           0 :       return true;
     101             :     }
     102           0 :     sys::fs::remove(Filename);
     103           0 :     errs() << " done. \n";
     104             :   } else {
     105           0 :     sys::ExecuteNoWait(ExecPath, args, None, {}, 0, &ErrMsg);
     106           0 :     errs() << "Remember to erase graph file: " << Filename << "\n";
     107             :   }
     108             :   return false;
     109             : }
     110             : 
     111             : namespace {
     112             : 
     113           0 : struct GraphSession {
     114             :   std::string LogBuffer;
     115             : 
     116           0 :   bool TryFindProgram(StringRef Names, std::string &ProgramPath) {
     117           0 :     raw_string_ostream Log(LogBuffer);
     118             :     SmallVector<StringRef, 8> parts;
     119           0 :     Names.split(parts, '|');
     120           0 :     for (auto Name : parts) {
     121           0 :       if (ErrorOr<std::string> P = sys::findProgramByName(Name)) {
     122             :         ProgramPath = *P;
     123             :         return true;
     124             :       }
     125           0 :       Log << "  Tried '" << Name << "'\n";
     126             :     }
     127           0 :     return false;
     128             :   }
     129             : };
     130             : 
     131             : } // end anonymous namespace
     132             : 
     133             : static const char *getProgramName(GraphProgram::Name program) {
     134           0 :   switch (program) {
     135             :   case GraphProgram::DOT:
     136             :     return "dot";
     137           0 :   case GraphProgram::FDP:
     138             :     return "fdp";
     139           0 :   case GraphProgram::NEATO:
     140             :     return "neato";
     141           0 :   case GraphProgram::TWOPI:
     142             :     return "twopi";
     143           0 :   case GraphProgram::CIRCO:
     144             :     return "circo";
     145             :   }
     146           0 :   llvm_unreachable("bad kind");
     147             : }
     148             : 
     149           0 : bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
     150             :                         GraphProgram::Name program) {
     151             :   std::string Filename = FilenameRef;
     152             :   std::string ErrMsg;
     153             :   std::string ViewerPath;
     154             :   GraphSession S;
     155             : 
     156             : #ifdef __APPLE__
     157             :   wait &= !ViewBackground;
     158             :   if (S.TryFindProgram("open", ViewerPath)) {
     159             :     std::vector<StringRef> args;
     160             :     args.push_back(ViewerPath);
     161             :     if (wait)
     162             :       args.push_back("-W");
     163             :     args.push_back(Filename);
     164             :     errs() << "Trying 'open' program... ";
     165             :     if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
     166             :       return false;
     167             :   }
     168             : #endif
     169           0 :   if (S.TryFindProgram("xdg-open", ViewerPath)) {
     170             :     std::vector<StringRef> args;
     171           0 :     args.push_back(ViewerPath);
     172           0 :     args.push_back(Filename);
     173           0 :     errs() << "Trying 'xdg-open' program... ";
     174           0 :     if (!ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg))
     175             :       return false;
     176             :   }
     177             : 
     178             :   // Graphviz
     179           0 :   if (S.TryFindProgram("Graphviz", ViewerPath)) {
     180             :     std::vector<StringRef> args;
     181           0 :     args.push_back(ViewerPath);
     182           0 :     args.push_back(Filename);
     183             : 
     184           0 :     errs() << "Running 'Graphviz' program... ";
     185           0 :     return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
     186             :   }
     187             : 
     188             :   // xdot
     189           0 :   if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) {
     190             :     std::vector<StringRef> args;
     191           0 :     args.push_back(ViewerPath);
     192           0 :     args.push_back(Filename);
     193             : 
     194           0 :     args.push_back("-f");
     195           0 :     args.push_back(getProgramName(program));
     196             : 
     197           0 :     errs() << "Running 'xdot.py' program... ";
     198           0 :     return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
     199             :   }
     200             : 
     201             :   enum ViewerKind {
     202             :     VK_None,
     203             :     VK_OSXOpen,
     204             :     VK_XDGOpen,
     205             :     VK_Ghostview,
     206             :     VK_CmdStart
     207             :   };
     208             :   ViewerKind Viewer = VK_None;
     209             : #ifdef __APPLE__
     210             :   if (!Viewer && S.TryFindProgram("open", ViewerPath))
     211             :     Viewer = VK_OSXOpen;
     212             : #endif
     213           0 :   if (!Viewer && S.TryFindProgram("gv", ViewerPath))
     214             :     Viewer = VK_Ghostview;
     215           0 :   if (!Viewer && S.TryFindProgram("xdg-open", ViewerPath))
     216             :     Viewer = VK_XDGOpen;
     217             : #ifdef _WIN32
     218             :   if (!Viewer && S.TryFindProgram("cmd", ViewerPath)) {
     219             :     Viewer = VK_CmdStart;
     220             :   }
     221             : #endif
     222             : 
     223             :   // PostScript or PDF graph generator + PostScript/PDF viewer
     224             :   std::string GeneratorPath;
     225           0 :   if (Viewer &&
     226           0 :       (S.TryFindProgram(getProgramName(program), GeneratorPath) ||
     227           0 :        S.TryFindProgram("dot|fdp|neato|twopi|circo", GeneratorPath))) {
     228             :     std::string OutputFilename =
     229           0 :         Filename + (Viewer == VK_CmdStart ? ".pdf" : ".ps");
     230             : 
     231             :     std::vector<StringRef> args;
     232           0 :     args.push_back(GeneratorPath);
     233             :     if (Viewer == VK_CmdStart)
     234             :       args.push_back("-Tpdf");
     235             :     else
     236           0 :       args.push_back("-Tps");
     237           0 :     args.push_back("-Nfontname=Courier");
     238           0 :     args.push_back("-Gsize=7.5,10");
     239           0 :     args.push_back(Filename);
     240           0 :     args.push_back("-o");
     241           0 :     args.push_back(OutputFilename);
     242             : 
     243           0 :     errs() << "Running '" << GeneratorPath << "' program... ";
     244             : 
     245           0 :     if (ExecGraphViewer(GeneratorPath, args, Filename, true, ErrMsg))
     246             :       return true;
     247             : 
     248             :     // The lifetime of StartArg must include the call of ExecGraphViewer
     249             :     // because the args are passed as vector of char*.
     250             :     std::string StartArg;
     251             : 
     252             :     args.clear();
     253           0 :     args.push_back(ViewerPath);
     254           0 :     switch (Viewer) {
     255             :     case VK_OSXOpen:
     256           0 :       args.push_back("-W");
     257           0 :       args.push_back(OutputFilename);
     258           0 :       break;
     259           0 :     case VK_XDGOpen:
     260             :       wait = false;
     261           0 :       args.push_back(OutputFilename);
     262           0 :       break;
     263             :     case VK_Ghostview:
     264           0 :       args.push_back("--spartan");
     265           0 :       args.push_back(OutputFilename);
     266           0 :       break;
     267             :     case VK_CmdStart:
     268           0 :       args.push_back("/S");
     269           0 :       args.push_back("/C");
     270             :       StartArg =
     271           0 :           (StringRef("start ") + (wait ? "/WAIT " : "") + OutputFilename).str();
     272           0 :       args.push_back(StartArg);
     273           0 :       break;
     274             :     case VK_None:
     275             :       llvm_unreachable("Invalid viewer");
     276             :     }
     277             : 
     278             :     ErrMsg.clear();
     279           0 :     return ExecGraphViewer(ViewerPath, args, OutputFilename, wait, ErrMsg);
     280             :   }
     281             : 
     282             :   // dotty
     283           0 :   if (S.TryFindProgram("dotty", ViewerPath)) {
     284             :     std::vector<StringRef> args;
     285           0 :     args.push_back(ViewerPath);
     286           0 :     args.push_back(Filename);
     287             : 
     288             : // Dotty spawns another app and doesn't wait until it returns
     289             : #ifdef _WIN32
     290             :     wait = false;
     291             : #endif
     292           0 :     errs() << "Running 'dotty' program... ";
     293           0 :     return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
     294             :   }
     295             : 
     296           0 :   errs() << "Error: Couldn't find a usable graph viewer program:\n";
     297           0 :   errs() << S.LogBuffer << "\n";
     298           0 :   return true;
     299             : }

Generated by: LCOV version 1.13