GraphWriter: detect graph viewer programs at runtime

Replace the crufty build-time configure checks for program paths with
equivalent runtime logic.

This lets users install graphing tools as needed without having to reconfigure
and rebuild LLVM, while eliminating a long chain of inappropriate compile
dependencies that included GUI programs and the windowing system.

Additional features:

 * Support the OS X 'open' command to view graphs generated by any of the
   Graphviz utilities. This is an alternative to the Graphviz OS X UI which is
   no longer available on Mountain Lion.

 * Produce informative log output upon failure to indicate which programs can
   be installed to view graphs.

Ping me if this doesn't work for your particular environment.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210001 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Alp Toker 2014-06-02 01:40:04 +00:00
parent df1913982b
commit 04de60e28f
9 changed files with 131 additions and 368 deletions

View File

@ -1282,16 +1282,6 @@ AC_PATH_PROG(TAR, [tar], [gtar])
AC_PATH_PROG(BINPWD,[pwd], [pwd])
dnl Looking for misc. graph plotting software
AC_PATH_PROG(GRAPHVIZ, [Graphviz], [echo Graphviz])
if test "$GRAPHVIZ" != "echo Graphviz" ; then
AC_DEFINE([HAVE_GRAPHVIZ],[1],[Define if the Graphviz program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
GRAPHVIZ=`echo $GRAPHVIZ | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_GRAPHVIZ],"$GRAPHVIZ${EXEEXT}",
[Define to path to Graphviz program if found or 'echo Graphviz' otherwise])
fi
AC_PATH_PROG(DOT, [dot], [echo dot])
if test "$DOT" != "echo dot" ; then
AC_DEFINE([HAVE_DOT],[1],[Define if the dot program is available])
@ -1302,76 +1292,6 @@ if test "$DOT" != "echo dot" ; then
AC_DEFINE_UNQUOTED([LLVM_PATH_DOT],"$DOT${EXEEXT}",
[Define to path to dot program if found or 'echo dot' otherwise])
fi
AC_PATH_PROG(FDP, [fdp], [echo fdp])
if test "$FDP" != "echo fdp" ; then
AC_DEFINE([HAVE_FDP],[1],[Define if the neat program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
FDP=`echo $FDP | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_FDP],"$FDP${EXEEXT}",
[Define to path to fdp program if found or 'echo fdp' otherwise])
fi
AC_PATH_PROG(NEATO, [neato], [echo neato])
if test "$NEATO" != "echo neato" ; then
AC_DEFINE([HAVE_NEATO],[1],[Define if the neat program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
NEATO=`echo $NEATO | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_NEATO],"$NEATO${EXEEXT}",
[Define to path to neato program if found or 'echo neato' otherwise])
fi
AC_PATH_PROG(TWOPI, [twopi], [echo twopi])
if test "$TWOPI" != "echo twopi" ; then
AC_DEFINE([HAVE_TWOPI],[1],[Define if the neat program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
TWOPI=`echo $TWOPI | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_TWOPI],"$TWOPI${EXEEXT}",
[Define to path to twopi program if found or 'echo twopi' otherwise])
fi
AC_PATH_PROG(CIRCO, [circo], [echo circo])
if test "$CIRCO" != "echo circo" ; then
AC_DEFINE([HAVE_CIRCO],[1],[Define if the neat program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
CIRCO=`echo $CIRCO | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_CIRCO],"$CIRCO${EXEEXT}",
[Define to path to circo program if found or 'echo circo' otherwise])
fi
AC_PATH_PROGS(GV, [gv gsview32], [echo gv])
if test "$GV" != "echo gv" ; then
AC_DEFINE([HAVE_GV],[1],[Define if the gv program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
GV=`echo $GV | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_GV],"$GV${EXEEXT}",
[Define to path to gv program if found or 'echo gv' otherwise])
fi
AC_PATH_PROG(DOTTY, [dotty], [echo dotty])
if test "$DOTTY" != "echo dotty" ; then
AC_DEFINE([HAVE_DOTTY],[1],[Define if the dotty program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
DOTTY=`echo $DOTTY | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_DOTTY],"$DOTTY${EXEEXT}",
[Define to path to dotty program if found or 'echo dotty' otherwise])
fi
AC_PATH_PROGS(XDOT, [xdot xdot.py], [echo xdot])
if test "$XDOT" != "echo xdot" ; then
AC_DEFINE([HAVE_XDOT],[1],[Define if the xdot program is available])
dnl If we're targeting for mingw we should emit windows paths, not msys
if test "$llvm_cv_os_type" = "MingW" ; then
XDOT=`echo $XDOT | sed 's/^\/\([[A-Za-z]]\)\//\1:\//' `
fi
AC_DEFINE_UNQUOTED([LLVM_PATH_XDOT],"$XDOT${EXEEXT}",
[Define to path to xdot program if found or 'echo xdot' otherwise])
fi
dnl Find the install program
AC_PROG_INSTALL

View File

@ -252,15 +252,9 @@ function(llvm_find_program name)
endif(LLVM_PATH_${NAME})
endfunction()
llvm_find_program(gv)
llvm_find_program(circo)
llvm_find_program(twopi)
llvm_find_program(neato)
llvm_find_program(fdp)
llvm_find_program(dot)
llvm_find_program(dotty)
llvm_find_program(xdot xdot.py)
llvm_find_program(Graphviz)
if (LLVM_ENABLE_DOXYGEN)
llvm_find_program(dot)
endif ()
if( LLVM_ENABLE_FFI )
find_path(FFI_INCLUDE_PATH ffi.h PATHS ${FFI_INCLUDE_DIR})

View File

@ -545,14 +545,15 @@ methods. Within GDB, for example, you can usually use something like ``call
DAG.viewGraph()`` to pop up a window. Alternatively, you can sprinkle calls to
these functions in your code in places you want to debug.
Getting this to work requires a small amount of configuration. On Unix systems
Getting this to work requires a small amount of setup. On Unix systems
with X11, install the `graphviz <http://www.graphviz.org>`_ toolkit, and make
sure 'dot' and 'gv' are in your path. If you are running on Mac OS X, download
and install the Mac OS X `Graphviz program
<http://www.pixelglow.com/graphviz/>`_ and add
``/Applications/Graphviz.app/Contents/MacOS/`` (or wherever you install it) to
your path. Once in your system and path are set up, rerun the LLVM configure
script and rebuild LLVM to enable this functionality.
your path. The programs need not be present when configuring, building or
running LLVM and can simply be installed when needed during an active debug
session.
``SelectionDAG`` has been extended to make it easier to locate *interesting*
nodes in large complex graphs. From gdb, if you ``call DAG.setGraphColor(node,

View File

@ -45,9 +45,6 @@
/* Define to 1 if you have the `ceilf' function. */
#cmakedefine HAVE_CEILF ${HAVE_CEILF}
/* Define if the neat program is available */
#cmakedefine HAVE_CIRCO ${HAVE_CIRCO}
/* Define to 1 if you have the `closedir' function. */
#cmakedefine HAVE_CLOSEDIR ${HAVE_CLOSEDIR}
@ -80,12 +77,6 @@
/* Define if dlopen() is available on this platform. */
#cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN}
/* Define if the dot program is available */
#cmakedefine HAVE_DOT ${HAVE_DOT}
/* Define if the dotty program is available */
#cmakedefine HAVE_DOTTY ${HAVE_DOTTY}
/* Define if you have the _dyld_func_lookup function. */
#undef HAVE_DYLD
@ -98,9 +89,6 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#cmakedefine HAVE_FCNTL_H ${HAVE_FCNTL_H}
/* Define if the neat program is available */
#cmakedefine HAVE_FDP ${HAVE_FDP}
/* Define to 1 if you have the <fenv.h> header file. */
#cmakedefine HAVE_FENV_H ${HAVE_FENV_H}
@ -161,12 +149,6 @@
/* Define to 1 if you have the `gettimeofday' function. */
#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY}
/* Define if the Graphviz program is available */
#cmakedefine HAVE_GRAPHVIZ ${HAVE_GRAPHVIZ}
/* Define if the gv program is available */
#cmakedefine HAVE_GV ${HAVE_GV}
/* Define to 1 if the system has the type `int64_t'. */
#cmakedefine HAVE_INT64_T ${HAVE_INT64_T}
@ -271,9 +253,6 @@
/* Define to 1 if you have the `nearbyintf' function. */
#cmakedefine HAVE_NEARBYINTF ${HAVE_NEARBYINTF}
/* Define if the neat program is available */
#cmakedefine HAVE_NEATO ${HAVE_NEATO}
/* Define to 1 if you have the `opendir' function. */
#cmakedefine HAVE_OPENDIR ${HAVE_OPENDIR}
@ -417,9 +396,6 @@
/* Define to 1 if you have the <termios.h> header file. */
#cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H}
/* Define if the neat program is available */
#cmakedefine HAVE_TWOPI ${HAVE_TWOPI}
/* Define to 1 if the system has the type `uint64_t'. */
#cmakedefine HAVE_UINT64_T ${HAVE_UINT64_T}
@ -438,9 +414,6 @@
/* Define to 1 if you have the `writev' function. */
#cmakedefine HAVE_WRITEV ${HAVE_WRITEV}
/* Define if the xdot.py program is available */
#cmakedefine HAVE_XDOT ${HAVE_XDOT}
/* Define to 1 if you have the <zlib.h> header file. */
#cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H}
@ -567,33 +540,6 @@
/* Define if this is Win32ish platform */
#cmakedefine LLVM_ON_WIN32 ${LLVM_ON_WIN32}
/* Define to path to circo program if found or 'echo circo' otherwise */
#cmakedefine LLVM_PATH_CIRCO "${LLVM_PATH_CIRCO}"
/* Define to path to dot program if found or 'echo dot' otherwise */
#cmakedefine LLVM_PATH_DOT "${LLVM_PATH_DOT}"
/* Define to path to dotty program if found or 'echo dotty' otherwise */
#cmakedefine LLVM_PATH_DOTTY "${LLVM_PATH_DOTTY}"
/* Define to path to fdp program if found or 'echo fdp' otherwise */
#cmakedefine LLVM_PATH_FDP "${LLVM_PATH_FDP}"
/* Define to path to Graphviz program if found or 'echo Graphviz' otherwise */
#cmakedefine LLVM_PATH_GRAPHVIZ "${LLVM_PATH_GRAPHVIZ}"
/* Define to path to gv program if found or 'echo gv' otherwise */
#cmakedefine LLVM_PATH_GV "${LLVM_PATH_GV}"
/* Define to path to neato program if found or 'echo neato' otherwise */
#cmakedefine LLVM_PATH_NEATO "${LLVM_PATH_NEATO}"
/* Define to path to twopi program if found or 'echo twopi' otherwise */
#cmakedefine LLVM_PATH_TWOPI "${LLVM_PATH_TWOPI}"
/* Define to path to xdot.py program if found or 'echo xdot' otherwise */
#cmakedefine LLVM_PATH_XDOT "${LLVM_PATH_XDOT}"
/* Installation prefix directory */
#cmakedefine LLVM_PREFIX "${LLVM_PREFIX}"

View File

@ -39,9 +39,6 @@
/* Define to 1 if you have the `ceilf' function. */
#undef HAVE_CEILF
/* Define if the neat program is available */
#undef HAVE_CIRCO
/* Define to 1 if you have the <CrashReporterClient.h> header file. */
#undef HAVE_CRASHREPORTERCLIENT_H
@ -77,12 +74,6 @@
/* Define if dlopen() is available on this platform. */
#undef HAVE_DLOPEN
/* Define if the dot program is available */
#undef HAVE_DOT
/* Define if the dotty program is available */
#undef HAVE_DOTTY
/* Define to 1 if you have the <errno.h> header file. */
#undef HAVE_ERRNO_H
@ -98,9 +89,6 @@
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define if the neat program is available */
#undef HAVE_FDP
/* Define to 1 if you have the <fenv.h> header file. */
#undef HAVE_FENV_H
@ -143,12 +131,6 @@
/* Define to 1 if you have the `gettimeofday' function. */
#undef HAVE_GETTIMEOFDAY
/* Define if the Graphviz program is available */
#undef HAVE_GRAPHVIZ
/* Define if the gv program is available */
#undef HAVE_GV
/* Define to 1 if the system has the type `int64_t'. */
#undef HAVE_INT64_T
@ -259,9 +241,6 @@
/* Define to 1 if you have the `nearbyintf' function. */
#undef HAVE_NEARBYINTF
/* Define if the neat program is available */
#undef HAVE_NEATO
/* Define to 1 if you have the `posix_spawn' function. */
#undef HAVE_POSIX_SPAWN
@ -402,9 +381,6 @@
/* Define to 1 if you have the <termios.h> header file. */
#undef HAVE_TERMIOS_H
/* Define if the neat program is available */
#undef HAVE_TWOPI
/* Define to 1 if the system has the type `uint64_t'. */
#undef HAVE_UINT64_T
@ -423,9 +399,6 @@
/* Define to 1 if you have the `writev' function. */
#undef HAVE_WRITEV
/* Define if the xdot program is available */
#undef HAVE_XDOT
/* Define to 1 if you have the <zlib.h> header file. */
#undef HAVE_ZLIB_H
@ -549,33 +522,6 @@
/* Define if this is Win32ish platform */
#undef LLVM_ON_WIN32
/* Define to path to circo program if found or 'echo circo' otherwise */
#undef LLVM_PATH_CIRCO
/* Define to path to dot program if found or 'echo dot' otherwise */
#undef LLVM_PATH_DOT
/* Define to path to dotty program if found or 'echo dotty' otherwise */
#undef LLVM_PATH_DOTTY
/* Define to path to fdp program if found or 'echo fdp' otherwise */
#undef LLVM_PATH_FDP
/* Define to path to Graphviz program if found or 'echo Graphviz' otherwise */
#undef LLVM_PATH_GRAPHVIZ
/* Define to path to gv program if found or 'echo gv' otherwise */
#undef LLVM_PATH_GV
/* Define to path to neato program if found or 'echo neato' otherwise */
#undef LLVM_PATH_NEATO
/* Define to path to twopi program if found or 'echo twopi' otherwise */
#undef LLVM_PATH_TWOPI
/* Define to path to xdot program if found or 'echo xdot' otherwise */
#undef LLVM_PATH_XDOT
/* Installation prefix directory */
#undef LLVM_PREFIX

View File

@ -79,33 +79,6 @@
/* Define if this is Win32ish platform */
#cmakedefine LLVM_ON_WIN32 ${LLVM_ON_WIN32}
/* Define to path to circo program if found or 'echo circo' otherwise */
#cmakedefine LLVM_PATH_CIRCO "${LLVM_PATH_CIRCO}"
/* Define to path to dot program if found or 'echo dot' otherwise */
#cmakedefine LLVM_PATH_DOT "${LLVM_PATH_DOT}"
/* Define to path to dotty program if found or 'echo dotty' otherwise */
#cmakedefine LLVM_PATH_DOTTY "${LLVM_PATH_DOTTY}"
/* Define to path to fdp program if found or 'echo fdp' otherwise */
#cmakedefine LLVM_PATH_FDP "${LLVM_PATH_FDP}"
/* Define to path to Graphviz program if found or 'echo Graphviz' otherwise */
#cmakedefine LLVM_PATH_GRAPHVIZ "${LLVM_PATH_GRAPHVIZ}"
/* Define to path to gv program if found or 'echo gv' otherwise */
#cmakedefine LLVM_PATH_GV "${LLVM_PATH_GV}"
/* Define to path to neato program if found or 'echo neato' otherwise */
#cmakedefine LLVM_PATH_NEATO "${LLVM_PATH_NEATO}"
/* Define to path to twopi program if found or 'echo twopi' otherwise */
#cmakedefine LLVM_PATH_TWOPI "${LLVM_PATH_TWOPI}"
/* Define to path to xdot.py program if found or 'echo xdot.py' otherwise */
#cmakedefine LLVM_PATH_XDOT_PY "${LLVM_PATH_XDOT_PY}"
/* Installation prefix directory */
#cmakedefine LLVM_PREFIX "${LLVM_PREFIX}"

View File

@ -79,33 +79,6 @@
/* Define if this is Win32ish platform */
#undef LLVM_ON_WIN32
/* Define to path to circo program if found or 'echo circo' otherwise */
#undef LLVM_PATH_CIRCO
/* Define to path to dot program if found or 'echo dot' otherwise */
#undef LLVM_PATH_DOT
/* Define to path to dotty program if found or 'echo dotty' otherwise */
#undef LLVM_PATH_DOTTY
/* Define to path to fdp program if found or 'echo fdp' otherwise */
#undef LLVM_PATH_FDP
/* Define to path to Graphviz program if found or 'echo Graphviz' otherwise */
#undef LLVM_PATH_GRAPHVIZ
/* Define to path to gv program if found or 'echo gv' otherwise */
#undef LLVM_PATH_GV
/* Define to path to neato program if found or 'echo neato' otherwise */
#undef LLVM_PATH_NEATO
/* Define to path to twopi program if found or 'echo twopi' otherwise */
#undef LLVM_PATH_TWOPI
/* Define to path to xdot.py program if found or 'echo xdot.py' otherwise */
#undef LLVM_PATH_XDOT_PY
/* Installation prefix directory */
#undef LLVM_PREFIX

View File

@ -50,7 +50,7 @@ namespace GraphProgram {
};
}
void DisplayGraph(StringRef Filename, bool wait = true,
bool DisplayGraph(StringRef Filename, bool wait = true,
GraphProgram::Name program = GraphProgram::DOT);
template<typename GraphType>

View File

@ -78,148 +78,158 @@ std::string llvm::createGraphFilename(const Twine &Name, int &FD) {
return Filename.str();
}
// Execute the graph viewer. Return true if successful.
static bool LLVM_ATTRIBUTE_UNUSED
ExecGraphViewer(StringRef ExecPath, std::vector<const char*> &args,
StringRef Filename, bool wait, std::string &ErrMsg) {
// Execute the graph viewer. Return true if there were errors.
static bool ExecGraphViewer(StringRef ExecPath, std::vector<const char *> &args,
StringRef Filename, bool wait,
std::string &ErrMsg) {
assert(args.back() == nullptr);
if (wait) {
if (sys::ExecuteAndWait(ExecPath, &args[0],nullptr,nullptr,0,0,&ErrMsg)) {
if (sys::ExecuteAndWait(ExecPath, args.data(), nullptr, nullptr, 0, 0,
&ErrMsg)) {
errs() << "Error: " << ErrMsg << "\n";
return false;
return true;
}
sys::fs::remove(Filename);
errs() << " done. \n";
}
else {
sys::ExecuteNoWait(ExecPath, &args[0],nullptr,nullptr,0,&ErrMsg);
} else {
sys::ExecuteNoWait(ExecPath, args.data(), nullptr, nullptr, 0, &ErrMsg);
errs() << "Remember to erase graph file: " << Filename.str() << "\n";
}
return true;
return false;
}
void llvm::DisplayGraph(StringRef FilenameRef, bool wait,
struct GraphSession {
std::string LogBuffer;
bool TryFindProgram(StringRef Names, std::string &ProgramPath) {
raw_string_ostream Log(LogBuffer);
SmallVector<StringRef, 8> parts;
Names.split(parts, "|");
for (auto Name : parts) {
ProgramPath = sys::FindProgramByName(Name);
if (!ProgramPath.empty())
return true;
Log << " Tried '" << Name << "'\n";
}
return false;
}
};
static const char *getProgramName(GraphProgram::Name program) {
switch (program) {
case GraphProgram::DOT:
return "dot";
case GraphProgram::FDP:
return "fdp";
case GraphProgram::NEATO:
return "neato";
case GraphProgram::TWOPI:
return "twopi";
case GraphProgram::CIRCO:
return "circo";
}
}
bool llvm::DisplayGraph(StringRef FilenameRef, bool wait,
GraphProgram::Name program) {
std::string Filename = FilenameRef;
wait &= !ViewBackground;
std::string ErrMsg;
#if HAVE_GRAPHVIZ
std::string Graphviz(LLVM_PATH_GRAPHVIZ);
std::string ViewerPath;
GraphSession S;
std::vector<const char*> args;
args.push_back(Graphviz.c_str());
args.push_back(Filename.c_str());
args.push_back(nullptr);
// Graphviz
if (S.TryFindProgram("Graphviz", ViewerPath)) {
std::vector<const char *> args;
args.push_back(ViewerPath.c_str());
args.push_back(Filename.c_str());
args.push_back(nullptr);
errs() << "Running 'Graphviz' program... ";
if (!ExecGraphViewer(Graphviz, args, Filename, wait, ErrMsg))
return;
#elif HAVE_XDOT
std::vector<const char*> args;
args.push_back(LLVM_PATH_XDOT);
args.push_back(Filename.c_str());
switch (program) {
case GraphProgram::DOT: args.push_back("-f"); args.push_back("dot"); break;
case GraphProgram::FDP: args.push_back("-f"); args.push_back("fdp"); break;
case GraphProgram::NEATO: args.push_back("-f"); args.push_back("neato");break;
case GraphProgram::TWOPI: args.push_back("-f"); args.push_back("twopi");break;
case GraphProgram::CIRCO: args.push_back("-f"); args.push_back("circo");break;
errs() << "Running 'Graphviz' program... ";
return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
}
args.push_back(0);
// xdot
if (S.TryFindProgram("xdot|xdot.py", ViewerPath)) {
std::vector<const char *> args;
args.push_back(ViewerPath.c_str());
args.push_back(Filename.c_str());
errs() << "Running 'xdot.py' program... ";
if (!ExecGraphViewer(LLVM_PATH_XDOT, args, Filename, wait, ErrMsg))
return;
args.push_back("-f");
args.push_back(getProgramName(program));
#elif (HAVE_GV && (HAVE_DOT || HAVE_FDP || HAVE_NEATO || \
HAVE_TWOPI || HAVE_CIRCO))
std::string PSFilename = Filename + ".ps";
std::string prog;
args.push_back(nullptr);
// Set default grapher
#if HAVE_CIRCO
prog = LLVM_PATH_CIRCO;
#endif
#if HAVE_TWOPI
prog = LLVM_PATH_TWOPI;
#endif
#if HAVE_NEATO
prog = LLVM_PATH_NEATO;
#endif
#if HAVE_FDP
prog = LLVM_PATH_FDP;
#endif
#if HAVE_DOT
prog = LLVM_PATH_DOT;
errs() << "Running 'xdot.py' program... ";
return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
}
enum PSViewerKind { PSV_None, PSV_OSXOpen, PSV_Ghostview };
PSViewerKind PSViewer = PSV_None;
#ifdef __APPLE__
if (S.TryFindProgram("open", ViewerPath))
PSViewer = PSV_OSXOpen;
#endif
if (!PSViewer && S.TryFindProgram("gv", ViewerPath))
PSViewer = PSV_Ghostview;
// Find which program the user wants
#if HAVE_DOT
if (program == GraphProgram::DOT)
prog = LLVM_PATH_DOT;
#endif
#if (HAVE_FDP)
if (program == GraphProgram::FDP)
prog = LLVM_PATH_FDP;
#endif
#if (HAVE_NEATO)
if (program == GraphProgram::NEATO)
prog = LLVM_PATH_NEATO;
#endif
#if (HAVE_TWOPI)
if (program == GraphProgram::TWOPI)
prog = LLVM_PATH_TWOPI;
#endif
#if (HAVE_CIRCO)
if (program == GraphProgram::CIRCO)
prog = LLVM_PATH_CIRCO;
#endif
// PostScript graph generator + PostScript viewer
std::string GeneratorPath;
if (PSViewer &&
(S.TryFindProgram(getProgramName(program), GeneratorPath) ||
S.TryFindProgram("circo|twopi|neato|fdp|dot", GeneratorPath))) {
std::string PSFilename = Filename + ".ps";
std::vector<const char*> args;
args.push_back(prog.c_str());
args.push_back("-Tps");
args.push_back("-Nfontname=Courier");
args.push_back("-Gsize=7.5,10");
args.push_back(Filename.c_str());
args.push_back("-o");
args.push_back(PSFilename.c_str());
args.push_back(0);
std::vector<const char *> args;
args.push_back(GeneratorPath.c_str());
args.push_back("-Tps");
args.push_back("-Nfontname=Courier");
args.push_back("-Gsize=7.5,10");
args.push_back(Filename.c_str());
args.push_back("-o");
args.push_back(PSFilename.c_str());
args.push_back(nullptr);
errs() << "Running '" << prog << "' program... ";
errs() << "Running '" << GeneratorPath << "' program... ";
if (!ExecGraphViewer(prog, args, Filename, wait, ErrMsg))
return;
if (ExecGraphViewer(GeneratorPath, args, Filename, wait, ErrMsg))
return true;
std::string gv(LLVM_PATH_GV);
args.clear();
args.push_back(gv.c_str());
args.push_back(PSFilename.c_str());
args.push_back("--spartan");
args.push_back(0);
args.clear();
args.push_back(ViewerPath.c_str());
switch (PSViewer) {
case PSV_OSXOpen:
args.push_back("-W");
args.push_back(PSFilename.c_str());
break;
case PSV_Ghostview:
args.push_back("--spartan");
args.push_back(PSFilename.c_str());
break;
case PSV_None:
llvm_unreachable("Invalid viewer");
}
args.push_back(nullptr);
ErrMsg.clear();
if (!ExecGraphViewer(gv, args, PSFilename, wait, ErrMsg))
return;
ErrMsg.clear();
return ExecGraphViewer(ViewerPath, args, PSFilename, wait, ErrMsg);
}
#elif HAVE_DOTTY
std::string dotty(LLVM_PATH_DOTTY);
std::vector<const char*> args;
args.push_back(dotty.c_str());
args.push_back(Filename.c_str());
args.push_back(0);
// dotty
if (S.TryFindProgram("dotty", ViewerPath)) {
std::vector<const char *> args;
args.push_back(ViewerPath.c_str());
args.push_back(Filename.c_str());
args.push_back(nullptr);
// Dotty spawns another app and doesn't wait until it returns
#if defined (__MINGW32__) || defined (_WINDOWS)
wait = false;
#endif
errs() << "Running 'dotty' program... ";
if (!ExecGraphViewer(dotty, args, Filename, wait, ErrMsg))
return;
#else
(void)Filename;
(void)ErrMsg;
#ifdef LLVM_ON_WIN32
wait = false;
#endif
errs() << "Running 'dotty' program... ";
return ExecGraphViewer(ViewerPath, args, Filename, wait, ErrMsg);
}
errs() << "Error: Couldn't find a usable graph viewer program:\n";
errs() << S.LogBuffer << "\n";
return true;
}