This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, master has been updated
       via  f6dac38c1120660c589b218e9d55cef190089dae (commit)
       via  5417737fac3b6dce325a1e7b97267f974837da70 (commit)
       via  d61b8921acde5650dbe6d20ec7b77c6f7522c876 (commit)
       via  7aab792716bb647aac2b5802e6e21148471a0c79 (commit)
       via  84e14a52ff694b5fc28511bae68dbb1e39dde246 (commit)
       via  ac75886525c647ef7081dc11f6c0c128463b7ecd (commit)
       via  553658393c0e775efdec6b29b69c1274fb771e83 (commit)
      from  ea048ed66c488a57ff1fe4477e07b489bf235972 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=f6dac38c1120660c589b218e9d55cef190089dae
commit f6dac38c1120660c589b218e9d55cef190089dae
Merge: 5417737fac 7aab792716
Author:     Brad King <brad.k...@kitware.com>
AuthorDate: Thu Oct 17 13:55:23 2019 -0400
Commit:     Brad King <brad.k...@kitware.com>
CommitDate: Thu Oct 17 13:55:23 2019 -0400

    Merge branch 'release-3.16'


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5417737fac3b6dce325a1e7b97267f974837da70
commit 5417737fac3b6dce325a1e7b97267f974837da70
Merge: d61b8921ac 553658393c
Author:     Brad King <brad.k...@kitware.com>
AuthorDate: Thu Oct 17 17:54:11 2019 +0000
Commit:     Kitware Robot <kwro...@kitware.com>
CommitDate: Thu Oct 17 13:54:26 2019 -0400

    Merge topic 'graphviz'
    
    553658393c Graphviz: added test suite, fixes, enhancements
    
    Acked-by: Kitware Robot <kwro...@kitware.com>
    Acked-by: slodki <slodki_...@poczta.onet.pl>
    Merge-request: !3766


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=d61b8921acde5650dbe6d20ec7b77c6f7522c876
commit d61b8921acde5650dbe6d20ec7b77c6f7522c876
Merge: ea048ed66c ac75886525
Author:     Brad King <brad.k...@kitware.com>
AuthorDate: Thu Oct 17 17:52:28 2019 +0000
Commit:     Kitware Robot <kwro...@kitware.com>
CommitDate: Thu Oct 17 13:52:49 2019 -0400

    Merge topic 'doc-pch-compile-language'
    
    ac75886525 PCH: Document and test COMPILE_LANGUAGE genex for per-language 
header
    
    Acked-by: Kitware Robot <kwro...@kitware.com>
    Merge-request: !3925


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=553658393c0e775efdec6b29b69c1274fb771e83
commit 553658393c0e775efdec6b29b69c1274fb771e83
Author:     Corentin Plouet <coren...@plouet.name>
AuthorDate: Tue Oct 8 13:45:30 2019 +1100
Commit:     Corentin Plouet <coren...@plouet.name>
CommitDate: Tue Oct 8 13:45:56 2019 +1100

    Graphviz: added test suite, fixes, enhancements
    
    * Added a fairly comprehensive test suite
    * Separated the graph traversal logic from the Graphviz generation
      code by introducing a new class, cmLinkItemsGraphVisitor{.h,cxx}
    * Made the graph traversal logic less ad-hoc by using existing
      methods in the GlobalGenerator; this fixed a few bugs
    * Added support for new target types: custom targets, object
      and unknown libraries
    * Improved support for ALIAS libraries by showing the alias(es)
      in the graph
    * Introduced new flags to control those new libraries (consistent
      with existing flags)
    * Updated the documentation
    * Removed useless setting to set graph type in dot file
    * Improved the node/edge shapes (nicer, more consistent)
    * Added a legend to the graph
    * Some refactoring and cleanup of the Graphviz generation code
    * Added test and fix for issue 19746

diff --git a/Modules/CMakeGraphVizOptions.cmake 
b/Modules/CMakeGraphVizOptions.cmake
index 1911e7392e..be4a3be365 100644
--- a/Modules/CMakeGraphVizOptions.cmake
+++ b/Modules/CMakeGraphVizOptions.cmake
@@ -5,119 +5,145 @@
 CMakeGraphVizOptions
 --------------------
 
-The builtin graphviz support of CMake.
+The builtin Graphviz support of CMake.
 
-Variables specific to the graphviz support
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Generating Graphviz files
+^^^^^^^^^^^^^^^^^^^^^^^^^
 
-CMake
-can generate `graphviz <http://www.graphviz.org/>`_ files, showing the 
dependencies between the
-targets in a project and also external libraries which are linked
-against.  When CMake is run with the ``--graphviz=foo.dot`` option, it will
-produce:
+CMake can generate `Graphviz <https://www.graphviz.org/>`_ files showing the
+dependencies between the targets in a project, as well as external libraries
+which are linked against.
 
-* a ``foo.dot`` file showing all dependencies in the project
-* a ``foo.dot.<target>`` file for each target, file showing on which other 
targets the respective target depends
-* a ``foo.dot.<target>.dependers`` file, showing which other targets depend on 
the respective target
+When running CMake with the ``--graphviz=foo.dot`` option, it produces:
 
-The different dependency types ``PUBLIC``, ``PRIVATE`` and ``INTERFACE``
-are represented as solid, dashed and dotted edges.
+* a ``foo.dot`` file, showing all dependencies in the project
+* a ``foo.dot.<target>`` file for each target, showing on which other targets
+  it depends
+* a ``foo.dot.<target>.dependers`` file for each target, showing which other
+  targets depend on it
 
-This can result in huge graphs.  Using the file
-``CMakeGraphVizOptions.cmake`` the look and content of the generated
-graphs can be influenced.  This file is searched first in
-:variable:`CMAKE_BINARY_DIR` and then in :variable:`CMAKE_SOURCE_DIR`.  If 
found, it is
-read and the variables set in it are used to adjust options for the
-generated graphviz files.
+Those .dot files can be converted to images using the *dot* command from the
+Graphviz package:
 
-.. variable:: GRAPHVIZ_GRAPH_TYPE
+.. code-block:: shell
 
- The graph type.
+  dot -Tpng -o foo.png foo.dot
 
- * Mandatory : NO
- * Default   : "digraph"
+The different dependency types ``PUBLIC``, ``INTERFACE`` and ``PRIVATE``
+are represented as solid, dashed and dotted edges.
 
- Valid graph types are:
+Variables specific to the Graphviz support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
- * "graph" : Nodes are joined with lines
- * "digraph" : Nodes are joined with arrows showing direction
- * "strict graph" : Like "graph" but max one line between each node
- * "strict digraph" : Like "graph" but max one line between each node in each 
direction
+The resulting graphs can be huge.  The look and content of the generated graphs
+can be controlled using the file ``CMakeGraphVizOptions.cmake``.  This file is
+first searched in :variable:`CMAKE_BINARY_DIR`, and then in
+:variable:`CMAKE_SOURCE_DIR`.  If found, the variables set in it are used to
+adjust options for the generated Graphviz files.
 
 .. variable:: GRAPHVIZ_GRAPH_NAME
 
  The graph name.
 
- * Mandatory : NO
- * Default   : "GG"
+ * Mandatory: NO
+ * Default: value of :variable:`CMAKE_PROJECT_NAME`
 
 .. variable:: GRAPHVIZ_GRAPH_HEADER
 
- The header written at the top of the graphviz file.
+ The header written at the top of the Graphviz files.
 
- * Mandatory : NO
- * Default   : "node [n  fontsize = "12"];"
+ * Mandatory: NO
+ * Default: "node [ fontsize = "12" ];"
 
 .. variable:: GRAPHVIZ_NODE_PREFIX
 
- The prefix for each node in the graphviz file.
+ The prefix for each node in the Graphviz files.
 
- * Mandatory : NO
- * Default   : "node"
+ * Mandatory: NO
+ * Default: "node"
 
 .. variable:: GRAPHVIZ_EXECUTABLES
 
- Set this to FALSE to exclude executables from the generated graphs.
+ Set to FALSE to exclude executables from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_STATIC_LIBS
 
- Set this to FALSE to exclude static libraries from the generated graphs.
+ Set to FALSE to exclude static libraries from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_SHARED_LIBS
 
- Set this to FALSE to exclude shared libraries from the generated graphs.
+ Set to FALSE to exclude shared libraries from the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_MODULE_LIBS
 
- Set this to FALSE to exclude module libraries from the generated graphs.
+ Set to FALSE to exclude module libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_INTERFACE_LIBS
+
+ Set to FALSE to exclude interface libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
 
- * Mandatory : NO
- * Default   : TRUE
+.. variable:: GRAPHVIZ_OBJECT_LIBS
+
+ Set to FALSE to exclude object libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_UNKNOWN_LIBS
+
+ Set to FALSE to exclude unknown libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_EXTERNAL_LIBS
 
- Set this to FALSE to exclude external libraries from the generated graphs.
+ Set to FALSE to exclude external libraries from the generated graphs.
+
+ * Mandatory: NO
+ * Default: TRUE
+
+.. variable:: GRAPHVIZ_CUSTOM_TARGETS
+
+ Set to TRUE to include custom targets in the generated graphs.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: FALSE
 
 .. variable:: GRAPHVIZ_IGNORE_TARGETS
 
- A list of regular expressions for ignoring targets.
+ A list of regular expressions for names of targets to exclude from the
+ generated graphs.
 
- * Mandatory : NO
- * Default   : empty
+ * Mandatory: NO
+ * Default: empty
 
 .. variable:: GRAPHVIZ_GENERATE_PER_TARGET
 
- Set this to FALSE to exclude per target graphs ``foo.dot.<target>``.
+ Set to FALSE to not generate per-target graphs ``foo.dot.<target>``.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 
 .. variable:: GRAPHVIZ_GENERATE_DEPENDERS
 
- Set this to FALSE to exclude depender graphs ``foo.dot.<target>.dependers``.
+ Set to FALSE to not generate depender graphs ``foo.dot.<target>.dependers``.
 
- * Mandatory : NO
- * Default   : TRUE
+ * Mandatory: NO
+ * Default: TRUE
 #]=======================================================================]
diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index 63e08de0f5..6087e53a29 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -289,6 +289,8 @@ set(SRCS
   cmGeneratorExpression.h
   cmGeneratorTarget.cxx
   cmGeneratorTarget.h
+  cmLinkItemGraphVisitor.cxx
+  cmLinkItemGraphVisitor.h
   cmGetPipes.cxx
   cmGetPipes.h
   cmGlobalCommonGenerator.cxx
diff --git a/Source/cmGraphVizWriter.cxx b/Source/cmGraphVizWriter.cxx
index e0d545d86d..7759c5f9d3 100644
--- a/Source/cmGraphVizWriter.cxx
+++ b/Source/cmGraphVizWriter.cxx
@@ -2,174 +2,190 @@
    file Copyright.txt or https://cmake.org/licensing for details.  */
 #include "cmGraphVizWriter.h"
 
-#include <cstddef>
+#include <cctype>
 #include <iostream>
 #include <memory>
-#include <sstream>
+#include <set>
 #include <utility>
 
+#include <cm/memory>
+
 #include "cmGeneratedFileStream.h"
 #include "cmGeneratorTarget.h"
 #include "cmGlobalGenerator.h"
+#include "cmLinkItem.h"
 #include "cmLocalGenerator.h"
 #include "cmMakefile.h"
 #include "cmState.h"
 #include "cmStateSnapshot.h"
 #include "cmStringAlgorithms.h"
 #include "cmSystemTools.h"
-#include "cmTarget.h"
 #include "cmake.h"
 
 namespace {
-enum LinkLibraryScopeType
-{
-  LLT_SCOPE_PUBLIC,
-  LLT_SCOPE_PRIVATE,
-  LLT_SCOPE_INTERFACE
-};
 
-const char* const GRAPHVIZ_PRIVATE_EDEGE_STYLE = "dashed";
-const char* const GRAPHVIZ_INTERFACE_EDEGE_STYLE = "dotted";
+char const* const GRAPHVIZ_EDGE_STYLE_PUBLIC = "solid";
+char const* const GRAPHVIZ_EDGE_STYLE_INTERFACE = "dashed";
+char const* const GRAPHVIZ_EDGE_STYLE_PRIVATE = "dotted";
 
-std::string getLinkLibraryStyle(const LinkLibraryScopeType& type)
-{
-  std::string style;
-  switch (type) {
-    case LLT_SCOPE_PRIVATE:
-      style = "[style = " + std::string(GRAPHVIZ_PRIVATE_EDEGE_STYLE) + "]";
-      break;
-    case LLT_SCOPE_INTERFACE:
-      style = "[style = " + std::string(GRAPHVIZ_INTERFACE_EDEGE_STYLE) + "]";
-      break;
-    default:
-      break;
-  }
-  return style;
-}
+char const* const GRAPHVIZ_NODE_SHAPE_EXECUTABLE = "egg"; // egg-xecutable
+
+// Normal libraries.
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC = "octagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED = "doubleoctagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE = "tripleoctagon";
 
-const char* getShapeForTarget(const cmGeneratorTarget* target)
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE = "pentagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT = "hexagon";
+char const* const GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN = "septagon";
+
+char const* const GRAPHVIZ_NODE_SHAPE_UTILITY = "box";
+
+const char* getShapeForTarget(const cmLinkItem& item)
 {
-  if (!target) {
-    return "ellipse";
+  if (item.Target == nullptr) {
+    return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN;
   }
 
-  switch (target->GetType()) {
+  switch (item.Target->GetType()) {
     case cmStateEnums::EXECUTABLE:
-      return "house";
+      return GRAPHVIZ_NODE_SHAPE_EXECUTABLE;
     case cmStateEnums::STATIC_LIBRARY:
-      return "diamond";
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC;
     case cmStateEnums::SHARED_LIBRARY:
-      return "polygon";
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED;
     case cmStateEnums::MODULE_LIBRARY:
-      return "octagon";
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE;
+    case cmStateEnums::OBJECT_LIBRARY:
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT;
+    case cmStateEnums::UTILITY:
+      return GRAPHVIZ_NODE_SHAPE_UTILITY;
+    case cmStateEnums::INTERFACE_LIBRARY:
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE;
+    case cmStateEnums::UNKNOWN_LIBRARY:
     default:
-      break;
+      return GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN;
   }
+}
+}
 
-  return "box";
+cmGraphVizWriter::cmGraphVizWriter(std::string const& fileName,
+                                   const cmGlobalGenerator* globalGenerator)
+  : FileName(fileName)
+  , GlobalFileStream(fileName)
+  , GraphName(globalGenerator->GetSafeGlobalSetting("CMAKE_PROJECT_NAME"))
+  , GraphHeader("node [\n  fontsize = \"12\"\n];")
+  , GraphNodePrefix("node")
+  , GlobalGenerator(globalGenerator)
+  , NextNodeId(0)
+  , GenerateForExecutables(true)
+  , GenerateForStaticLibs(true)
+  , GenerateForSharedLibs(true)
+  , GenerateForModuleLibs(true)
+  , GenerateForInterfaceLibs(true)
+  , GenerateForObjectLibs(true)
+  , GenerateForUnknownLibs(true)
+  , GenerateForCustomTargets(false)
+  , GenerateForExternals(true)
+  , GeneratePerTarget(true)
+  , GenerateDependers(true)
+{
 }
 
-std::map<std::string, LinkLibraryScopeType> getScopedLinkLibrariesFromTarget(
-  cmTarget* Target, const cmGlobalGenerator* globalGenerator)
+cmGraphVizWriter::~cmGraphVizWriter()
 {
-  char sep = ';';
-  std::map<std::string, LinkLibraryScopeType> tokens;
-  size_t start = 0;
-  size_t end = 0;
+  this->WriteFooter(this->GlobalFileStream);
 
-  const char* pInterfaceLinkLibraries =
-    Target->GetProperty("INTERFACE_LINK_LIBRARIES");
-  const char* pLinkLibraries = Target->GetProperty("LINK_LIBRARIES");
+  for (auto& fileStream : this->PerTargetFileStreams) {
+    this->WriteFooter(*fileStream.second);
+  }
 
-  if (!pInterfaceLinkLibraries && !pLinkLibraries) {
-    return tokens; // target is not linked against any other libraries
+  for (auto& fileStream : this->TargetDependersFileStreams) {
+    this->WriteFooter(*fileStream.second);
   }
+}
 
-  // make sure we don't touch a null-ptr
-  auto interfaceLinkLibraries =
-    std::string(pInterfaceLinkLibraries ? pInterfaceLinkLibraries : "");
-  auto linkLibraries = std::string(pLinkLibraries ? pLinkLibraries : "");
+void cmGraphVizWriter::VisitGraph(std::string const&)
+{
+  this->WriteHeader(GlobalFileStream, this->GraphName);
+  this->WriteLegend(GlobalFileStream);
+}
 
-  // first extract interfaceLinkLibraries
-  while (start < interfaceLinkLibraries.length()) {
+void cmGraphVizWriter::OnItem(cmLinkItem const& item)
+{
+  if (this->ItemExcluded(item)) {
+    return;
+  }
 
-    if ((end = interfaceLinkLibraries.find(sep, start)) == std::string::npos) {
-      end = interfaceLinkLibraries.length();
-    }
+  NodeNames[item.AsStr()] = cmStrCat(GraphNodePrefix, NextNodeId);
+  ++NextNodeId;
 
-    std::string element = interfaceLinkLibraries.substr(start, end - start);
-    if (globalGenerator->IsAlias(element)) {
-      const auto tgt = globalGenerator->FindTarget(element);
-      if (tgt) {
-        element = tgt->GetName();
-      }
-    }
+  this->WriteNode(this->GlobalFileStream, item);
 
-    if (std::string::npos == element.find("$<LINK_ONLY:", 0)) {
-      // we assume first, that this library is an interface library.
-      // if we find it again in the linklibraries property, we promote it to an
-      // public library.
-      tokens[element] = LLT_SCOPE_INTERFACE;
-    } else {
-      // this is an private linked static library.
-      // we take care of this case in the second iterator.
-    }
-    start = end + 1;
+  if (this->GeneratePerTarget) {
+    this->CreateTargetFile(this->PerTargetFileStreams, item);
   }
 
-  // second extract linkLibraries
-  start = 0;
-  while (start < linkLibraries.length()) {
-
-    if ((end = linkLibraries.find(sep, start)) == std::string::npos) {
-      end = linkLibraries.length();
-    }
+  if (this->GenerateDependers) {
+    this->CreateTargetFile(this->TargetDependersFileStreams, item,
+                           ".dependers");
+  }
+}
 
-    std::string element = linkLibraries.substr(start, end - start);
-    if (globalGenerator->IsAlias(element)) {
-      const auto tgt = globalGenerator->FindTarget(element);
-      if (tgt) {
-        element = tgt->GetName();
-      }
-    }
+void cmGraphVizWriter::CreateTargetFile(FileStreamMap& fileStreamMap,
+                                        cmLinkItem const& item,
+                                        std::string const& fileNameSuffix)
+{
+  auto const pathSafeItemName = PathSafeString(item.AsStr());
+  auto const perTargetFileName =
+    cmStrCat(this->FileName, '.', pathSafeItemName, fileNameSuffix);
+  auto perTargetFileStream =
+    cm::make_unique<cmGeneratedFileStream>(perTargetFileName);
 
-    if (tokens.find(element) == tokens.end()) {
-      // this library is not found in interfaceLinkLibraries but in
-      // linkLibraries.
-      // this results in a private linked library.
-      tokens[element] = LLT_SCOPE_PRIVATE;
-    } else if (LLT_SCOPE_INTERFACE == tokens[element]) {
-      // this library is found in interfaceLinkLibraries and linkLibraries.
-      // this results in a public linked library.
-      tokens[element] = LLT_SCOPE_PUBLIC;
-    } else {
-      // private and public linked libraries should not be changed anymore.
-    }
+  this->WriteHeader(*perTargetFileStream, item.AsStr());
+  this->WriteNode(*perTargetFileStream, item);
 
-    start = end + 1;
-  }
+  fileStreamMap.emplace(item.AsStr(), std::move(perTargetFileStream));
+}
 
-  return tokens;
+void cmGraphVizWriter::OnDirectLink(cmLinkItem const& depender,
+                                    cmLinkItem const& dependee,
+                                    DependencyType dt)
+{
+  this->VisitLink(depender, dependee, true, GetEdgeStyle(dt));
 }
+
+void cmGraphVizWriter::OnIndirectLink(cmLinkItem const& depender,
+                                      cmLinkItem const& dependee)
+{
+  this->VisitLink(depender, dependee, false);
 }
 
-cmGraphVizWriter::cmGraphVizWriter(const cmGlobalGenerator* globalGenerator)
-  : GraphType("digraph")
-  , GraphName("GG")
-  , GraphHeader("node [\n  fontsize = \"12\"\n];")
-  , GraphNodePrefix("node")
-  , GlobalGenerator(globalGenerator)
-  , LocalGenerators(globalGenerator->GetLocalGenerators())
-  , GenerateForExecutables(true)
-  , GenerateForStaticLibs(true)
-  , GenerateForSharedLibs(true)
-  , GenerateForModuleLibs(true)
-  , GenerateForInterface(true)
-  , GenerateForExternals(true)
-  , GeneratePerTarget(true)
-  , GenerateDependers(true)
-  , HaveTargetsAndLibs(false)
+void cmGraphVizWriter::VisitLink(cmLinkItem const& depender,
+                                 cmLinkItem const& dependee, bool isDirectLink,
+                                 std::string const& scopeType)
 {
+  if (this->ItemExcluded(depender) || this->ItemExcluded(dependee)) {
+    return;
+  }
+
+  if (!isDirectLink) {
+    return;
+  }
+
+  this->WriteConnection(this->GlobalFileStream, depender, dependee, scopeType);
+
+  if (this->GeneratePerTarget) {
+    auto fileStream = PerTargetFileStreams[depender.AsStr()].get();
+    this->WriteNode(*fileStream, dependee);
+    this->WriteConnection(*fileStream, depender, dependee, scopeType);
+  }
+
+  if (this->GenerateDependers) {
+    auto fileStream = TargetDependersFileStreams[dependee.AsStr()].get();
+    this->WriteNode(*fileStream, depender);
+    this->WriteConnection(*fileStream, depender, dependee, scopeType);
+  }
 }
 
 void cmGraphVizWriter::ReadSettings(
@@ -208,7 +224,6 @@ void cmGraphVizWriter::ReadSettings(
     }                                                                         \
   } while (false)
 
-  __set_if_set(this->GraphType, "GRAPHVIZ_GRAPH_TYPE");
   __set_if_set(this->GraphName, "GRAPHVIZ_GRAPH_NAME");
   __set_if_set(this->GraphHeader, "GRAPHVIZ_GRAPH_HEADER");
   __set_if_set(this->GraphNodePrefix, "GRAPHVIZ_NODE_PREFIX");
@@ -225,7 +240,10 @@ void cmGraphVizWriter::ReadSettings(
   __set_bool_if_set(this->GenerateForStaticLibs, "GRAPHVIZ_STATIC_LIBS");
   __set_bool_if_set(this->GenerateForSharedLibs, "GRAPHVIZ_SHARED_LIBS");
   __set_bool_if_set(this->GenerateForModuleLibs, "GRAPHVIZ_MODULE_LIBS");
-  __set_bool_if_set(this->GenerateForInterface, "GRAPHVIZ_INTERFACE");
+  __set_bool_if_set(this->GenerateForInterfaceLibs, "GRAPHVIZ_INTERFACE_LIBS");
+  __set_bool_if_set(this->GenerateForObjectLibs, "GRAPHVIZ_OBJECT_LIBS");
+  __set_bool_if_set(this->GenerateForUnknownLibs, "GRAPHVIZ_UNKNOWN_LIBS");
+  __set_bool_if_set(this->GenerateForCustomTargets, "GRAPHVIZ_CUSTOM_TARGETS");
   __set_bool_if_set(this->GenerateForExternals, "GRAPHVIZ_EXTERNAL_LIBS");
   __set_bool_if_set(this->GeneratePerTarget, "GRAPHVIZ_GENERATE_PER_TARGET");
   __set_bool_if_set(this->GenerateDependers, "GRAPHVIZ_GENERATE_DEPENDERS");
@@ -248,329 +266,170 @@ void cmGraphVizWriter::ReadSettings(
   }
 }
 
-// Iterate over all targets and write for each one a graph which shows
-// which other targets depend on it.
-void cmGraphVizWriter::WriteTargetDependersFiles(const std::string& fileName)
+void cmGraphVizWriter::Write()
 {
-  if (!this->GenerateDependers) {
-    return;
-  }
-
-  this->CollectTargetsAndLibs();
-
-  for (auto const& ptr : this->TargetPtrs) {
-    if (ptr.second == nullptr) {
-      continue;
-    }
-
-    if (!this->GenerateForTargetType(ptr.second->GetType())) {
-      continue;
-    }
-
-    std::string currentFilename =
-      cmStrCat(fileName, '.', ptr.first, ".dependers");
-
-    cmGeneratedFileStream str(currentFilename);
-    if (!str) {
-      return;
+  auto gg = this->GlobalGenerator;
+
+  this->VisitGraph(gg->GetName());
+
+  // We want to traverse in a determined order, such that the output is always
+  // the same for a given project (this makes tests reproducible, etc.)
+  std::set<cmGeneratorTarget const*, cmGeneratorTarget::StrictTargetComparison>
+    sortedGeneratorTargets;
+
+  for (cmLocalGenerator const* lg : gg->GetLocalGenerators()) {
+    for (cmGeneratorTarget const* gt : lg->GetGeneratorTargets()) {
+      // Reserved targets have inconsistent names across platforms (e.g. 'all'
+      // vs. 'ALL_BUILD'), which can disrupt the traversal ordering.
+      // We don't need or want them anyway.
+      if (!cmGlobalGenerator::IsReservedTarget(gt->GetName())) {
+        sortedGeneratorTargets.insert(gt);
+      }
     }
-
-    std::set<std::string> insertedConnections;
-    std::set<std::string> insertedNodes;
-
-    std::cout << "Writing " << currentFilename << "..." << std::endl;
-    this->WriteHeader(str);
-
-    this->WriteDependerConnections(ptr.first, insertedNodes,
-                                   insertedConnections, str);
-
-    this->WriteFooter(str);
-  }
-}
-
-// Iterate over all targets and write for each one a graph which shows
-// on which targets it depends.
-void cmGraphVizWriter::WritePerTargetFiles(const std::string& fileName)
-{
-  if (!this->GeneratePerTarget) {
-    return;
   }
 
-  this->CollectTargetsAndLibs();
-
-  for (auto const& ptr : this->TargetPtrs) {
-    if (ptr.second == nullptr) {
-      continue;
-    }
-
-    if (!this->GenerateForTargetType(ptr.second->GetType())) {
-      continue;
-    }
-
-    std::set<std::string> insertedConnections;
-    std::set<std::string> insertedNodes;
-
-    std::string currentFilename = cmStrCat(fileName, '.', ptr.first);
-    cmGeneratedFileStream str(currentFilename);
-    if (!str) {
-      return;
-    }
-
-    std::cout << "Writing " << currentFilename << "..." << std::endl;
-    this->WriteHeader(str);
-
-    this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str);
-    this->WriteFooter(str);
+  for (auto const gt : sortedGeneratorTargets) {
+    auto item = cmLinkItem(gt, gt->GetBacktrace());
+    this->VisitItem(item);
   }
 }
 
-void cmGraphVizWriter::WriteGlobalFile(const std::string& fileName)
+void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& fs,
+                                   const std::string& name)
 {
-  this->CollectTargetsAndLibs();
-
-  cmGeneratedFileStream str(fileName);
-  if (!str) {
-    return;
-  }
-  this->WriteHeader(str);
-
-  std::cout << "Writing " << fileName << "..." << std::endl;
-
-  std::set<std::string> insertedConnections;
-  std::set<std::string> insertedNodes;
-
-  for (auto const& ptr : this->TargetPtrs) {
-    if (ptr.second == nullptr) {
-      continue;
-    }
-
-    if (!this->GenerateForTargetType(ptr.second->GetType())) {
-      continue;
-    }
-
-    this->WriteConnections(ptr.first, insertedNodes, insertedConnections, str);
-  }
-  this->WriteFooter(str);
+  auto const escapedGraphName = EscapeForDotFile(name);
+  fs << "digraph \"" << escapedGraphName << "\" {" << std::endl;
+  fs << this->GraphHeader << std::endl;
 }
 
-void cmGraphVizWriter::WriteHeader(cmGeneratedFileStream& str) const
+void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& fs)
 {
-  str << this->GraphType << " \"" << this->GraphName << "\" {" << std::endl;
-  str << this->GraphHeader << std::endl;
+  fs << "}" << std::endl;
 }
 
-void cmGraphVizWriter::WriteFooter(cmGeneratedFileStream& str) const
+void cmGraphVizWriter::WriteLegend(cmGeneratedFileStream& fs)
 {
-  str << "}" << std::endl;
+  // Note that the subgraph name must start with "cluster", as done here, to
+  // make Graphviz layout engines do the right thing and keep the nodes
+  // together.
+  fs << "subgraph clusterLegend {" << std::endl;
+  fs << "  label = \"Legend\";" << std::endl;
+  // Set the color of the box surrounding the legend.
+  fs << "  color = black;" << std::endl;
+  // We use invisible edges just to enforce the layout.
+  fs << "  edge [ style = invis ];" << std::endl;
+
+  // Nodes.
+  fs << "  legendNode0 [ label = \"Executable\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_EXECUTABLE << " ];" << std::endl;
+
+  fs << "  legendNode1 [ label = \"Static Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_STATIC << " ];" << std::endl;
+  fs << "  legendNode2 [ label = \"Shared Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_SHARED << " ];" << std::endl;
+  fs << "  legendNode3 [ label = \"Module Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_MODULE << " ];" << std::endl;
+
+  fs << "  legendNode4 [ label = \"Interface Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_INTERFACE << " ];" << std::endl;
+  fs << "  legendNode5 [ label = \"Object Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_OBJECT << " ];" << std::endl;
+  fs << "  legendNode6 [ label = \"Unknown Library\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_LIBRARY_UNKNOWN << " ];" << std::endl;
+
+  fs << "  legendNode7 [ label = \"Custom Target\", shape = "
+     << GRAPHVIZ_NODE_SHAPE_UTILITY << " ];" << std::endl;
+
+  // Edges.
+  // Some of those are dummy (invisible) edges to enforce a layout.
+  fs << "  legendNode0 -> legendNode1 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
+     << " ];" << std::endl;
+  fs << "  legendNode0 -> legendNode2 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
+     << " ];" << std::endl;
+  fs << "  legendNode0 -> legendNode3;" << std::endl;
+
+  fs << "  legendNode1 -> legendNode4 [ label = \"Interface\", style = "
+     << GRAPHVIZ_EDGE_STYLE_INTERFACE << " ];" << std::endl;
+  fs << "  legendNode2 -> legendNode5 [ label = \"Private\", style = "
+     << GRAPHVIZ_EDGE_STYLE_PRIVATE << " ];" << std::endl;
+  fs << "  legendNode3 -> legendNode6 [ style = " << GRAPHVIZ_EDGE_STYLE_PUBLIC
+     << " ];" << std::endl;
+
+  fs << "  legendNode0 -> legendNode7;" << std::endl;
+
+  fs << "}" << std::endl;
 }
 
-void cmGraphVizWriter::WriteConnections(
-  const std::string& targetName, std::set<std::string>& insertedNodes,
-  std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const
+void cmGraphVizWriter::WriteNode(cmGeneratedFileStream& fs,
+                                 cmLinkItem const& item)
 {
-  auto targetPtrIt = this->TargetPtrs.find(targetName);
+  auto const& itemName = item.AsStr();
+  auto const& nodeName = this->NodeNames[itemName];
 
-  if (targetPtrIt == this->TargetPtrs.end()) // not found at all
-  {
-    return;
-  }
-
-  this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str);
-
-  if (targetPtrIt->second == nullptr) // it's an external library
-  {
-    return;
-  }
+  auto const itemNameWithAliases = ItemNameWithAliases(itemName);
+  auto const escapedLabel = EscapeForDotFile(itemNameWithAliases);
 
-  std::string myNodeName = this->TargetNamesNodes.find(targetName)->second;
-  std::map<std::string, LinkLibraryScopeType> ll =
-    getScopedLinkLibrariesFromTarget(targetPtrIt->second->Target,
-                                     GlobalGenerator);
-
-  for (auto const& llit : ll) {
-    const std::string& libName = llit.first;
-    auto libNameIt = this->TargetNamesNodes.find(libName);
-
-    // can happen e.g. if GRAPHVIZ_TARGET_IGNORE_REGEX is used
-    if (libNameIt == this->TargetNamesNodes.end()) {
-      continue;
-    }
+  fs << "    \"" << nodeName << "\" [ label = \"" << escapedLabel
+     << "\", shape = " << getShapeForTarget(item) << " ];" << std::endl;
+}
 
-    std::string connectionName = cmStrCat(myNodeName, '-', libNameIt->second);
-    if (insertedConnections.find(connectionName) ==
-        insertedConnections.end()) {
-      insertedConnections.insert(connectionName);
-      this->WriteNode(libName, this->TargetPtrs.find(libName)->second,
-                      insertedNodes, str);
+void cmGraphVizWriter::WriteConnection(cmGeneratedFileStream& fs,
+                                       cmLinkItem const& depender,
+                                       cmLinkItem const& dependee,
+                                       std::string const& edgeStyle)
+{
+  auto const& dependerName = depender.AsStr();
+  auto const& dependeeName = dependee.AsStr();
 
-      str << "    \"" << myNodeName << "\" -> \"" << libNameIt->second << "\"";
+  fs << "    \"" << this->NodeNames[dependerName] << "\" -> \""
+     << this->NodeNames[dependeeName] << "\" ";
 
-      str << getLinkLibraryStyle(llit.second);
+  fs << edgeStyle;
 
-      str << " // " << targetName << " -> " << libName << std::endl;
-      this->WriteConnections(libName, insertedNodes, insertedConnections, str);
-    }
-  }
+  fs << " // " << dependerName << " -> " << dependeeName << std::endl;
 }
 
-void cmGraphVizWriter::WriteDependerConnections(
-  const std::string& targetName, std::set<std::string>& insertedNodes,
-  std::set<std::string>& insertedConnections, cmGeneratedFileStream& str) const
+bool cmGraphVizWriter::ItemExcluded(cmLinkItem const& item)
 {
-  auto targetPtrIt = this->TargetPtrs.find(targetName);
+  auto const itemName = item.AsStr();
 
-  if (targetPtrIt == this->TargetPtrs.end()) // not found at all
-  {
-    return;
+  if (this->ItemNameFilteredOut(itemName)) {
+    return true;
   }
 
-  this->WriteNode(targetName, targetPtrIt->second, insertedNodes, str);
-
-  if (targetPtrIt->second == nullptr) // it's an external library
-  {
-    return;
+  if (item.Target == nullptr) {
+    return !this->GenerateForExternals;
   }
 
-  std::string myNodeName = this->TargetNamesNodes.find(targetName)->second;
-
-  // now search who links against me
-  for (auto const& tptr : this->TargetPtrs) {
-    if (tptr.second == nullptr) {
-      continue;
-    }
-
-    if (!this->GenerateForTargetType(tptr.second->GetType())) {
-      continue;
-    }
-
-    // Now we have a target, check whether it links against targetName.
-    // If so, draw a connection, and then continue with dependers on that one.
-    std::map<std::string, LinkLibraryScopeType> ll =
-      getScopedLinkLibrariesFromTarget(tptr.second->Target, GlobalGenerator);
-
-    for (auto const& llit : ll) {
-      if (llit.first == targetName) {
-        // So this target links against targetName.
-        auto dependerNodeNameIt = this->TargetNamesNodes.find(tptr.first);
-
-        if (dependerNodeNameIt != this->TargetNamesNodes.end()) {
-          std::string connectionName =
-            cmStrCat(dependerNodeNameIt->second, '-', myNodeName);
-
-          if (insertedConnections.find(connectionName) ==
-              insertedConnections.end()) {
-            insertedConnections.insert(connectionName);
-            this->WriteNode(tptr.first, tptr.second, insertedNodes, str);
-
-            str << "    \"" << dependerNodeNameIt->second << "\" -> \""
-                << myNodeName << "\"";
-            str << " // " << targetName << " -> " << tptr.first << std::endl;
-            str << getLinkLibraryStyle(llit.second);
-            this->WriteDependerConnections(tptr.first, insertedNodes,
-                                           insertedConnections, str);
-          }
-        }
-        break;
-      }
+  if (item.Target->GetType() == cmStateEnums::UTILITY) {
+    if ((itemName.find("Nightly") == 0) ||
+        (itemName.find("Continuous") == 0) ||
+        (itemName.find("Experimental") == 0)) {
+      return true;
     }
   }
-}
 
-void cmGraphVizWriter::WriteNode(const std::string& targetName,
-                                 const cmGeneratorTarget* target,
-                                 std::set<std::string>& insertedNodes,
-                                 cmGeneratedFileStream& str) const
-{
-  if (insertedNodes.find(targetName) == insertedNodes.end()) {
-    insertedNodes.insert(targetName);
-    auto nameIt = this->TargetNamesNodes.find(targetName);
-
-    str << "    \"" << nameIt->second << "\" [ label=\"" << targetName
-        << "\" shape=\"" << getShapeForTarget(target) << "\"];" << std::endl;
+  if (item.Target->IsImported() && !this->GenerateForExternals) {
+    return true;
   }
-}
 
-void cmGraphVizWriter::CollectTargetsAndLibs()
-{
-  if (!this->HaveTargetsAndLibs) {
-    this->HaveTargetsAndLibs = true;
-    int cnt = this->CollectAllTargets();
-    if (this->GenerateForExternals) {
-      this->CollectAllExternalLibs(cnt);
-    }
-  }
+  return !this->TargetTypeEnabled(item.Target->GetType());
 }
 
-int cmGraphVizWriter::CollectAllTargets()
+bool cmGraphVizWriter::ItemNameFilteredOut(std::string const& itemName)
 {
-  int cnt = 0;
-  // First pass get the list of all cmake targets
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
-      const std::string& realTargetName = target->GetName();
-      if (this->IgnoreThisTarget(realTargetName)) {
-        // Skip ignored targets
-        continue;
-      }
-      // std::cout << "Found target: " << tit->first << std::endl;
-      std::ostringstream ostr;
-      ostr << this->GraphNodePrefix << cnt++;
-      this->TargetNamesNodes[realTargetName] = ostr.str();
-      this->TargetPtrs[realTargetName] = target;
-    }
+  if (itemName == ">") {
+    // FIXME: why do we even receive such a target here?
+    return true;
   }
 
-  return cnt;
-}
-
-int cmGraphVizWriter::CollectAllExternalLibs(int cnt)
-{
-  // Ok, now find all the stuff we link to that is not in cmake
-  for (cmLocalGenerator* lg : this->LocalGenerators) {
-    const std::vector<cmGeneratorTarget*>& targets = lg->GetGeneratorTargets();
-    for (cmGeneratorTarget* target : targets) {
-      const std::string& realTargetName = target->GetName();
-      if (this->IgnoreThisTarget(realTargetName)) {
-        // Skip ignored targets
-        continue;
-      }
-      const cmTarget::LinkLibraryVectorType* ll =
-        &(target->Target->GetOriginalLinkLibraries());
-      for (auto const& llit : *ll) {
-        std::string libName = llit.first;
-        if (this->IgnoreThisTarget(libName)) {
-          // Skip ignored targets
-          continue;
-        }
-
-        if (GlobalGenerator->IsAlias(libName)) {
-          const auto tgt = GlobalGenerator->FindTarget(libName);
-          if (tgt) {
-            libName = tgt->GetName();
-          }
-        }
-
-        auto tarIt = this->TargetPtrs.find(libName);
-        if (tarIt == this->TargetPtrs.end()) {
-          std::ostringstream ostr;
-          ostr << this->GraphNodePrefix << cnt++;
-          this->TargetNamesNodes[libName] = ostr.str();
-          this->TargetPtrs[libName] = nullptr;
-          // str << "    \"" << ostr << "\" [ label=\"" << libName
-          // <<  "\" shape=\"ellipse\"];" << std::endl;
-        }
-      }
-    }
+  if (cmGlobalGenerator::IsReservedTarget(itemName)) {
+    return true;
   }
-  return cnt;
-}
 
-bool cmGraphVizWriter::IgnoreThisTarget(const std::string& name)
-{
   for (cmsys::RegularExpression& regEx : this->TargetsToIgnoreRegex) {
     if (regEx.is_valid()) {
-      if (regEx.find(name)) {
+      if (regEx.find(itemName)) {
         return true;
       }
     }
@@ -579,7 +438,7 @@ bool cmGraphVizWriter::IgnoreThisTarget(const std::string& 
name)
   return false;
 }
 
-bool cmGraphVizWriter::GenerateForTargetType(
+bool cmGraphVizWriter::TargetTypeEnabled(
   cmStateEnums::TargetType targetType) const
 {
   switch (targetType) {
@@ -592,9 +451,73 @@ bool cmGraphVizWriter::GenerateForTargetType(
     case cmStateEnums::MODULE_LIBRARY:
       return this->GenerateForModuleLibs;
     case cmStateEnums::INTERFACE_LIBRARY:
-      return this->GenerateForInterface;
+      return this->GenerateForInterfaceLibs;
+    case cmStateEnums::OBJECT_LIBRARY:
+      return this->GenerateForObjectLibs;
+    case cmStateEnums::UNKNOWN_LIBRARY:
+      return this->GenerateForUnknownLibs;
+    case cmStateEnums::UTILITY:
+      return this->GenerateForCustomTargets;
+    case cmStateEnums::GLOBAL_TARGET:
+      // Built-in targets like edit_cache, etc.
+      // We don't need/want those in the dot file.
+      return false;
     default:
       break;
   }
   return false;
 }
+
+std::string cmGraphVizWriter::ItemNameWithAliases(
+  std::string const& itemName) const
+{
+  auto nameWithAliases = itemName;
+
+  for (auto const& lg : this->GlobalGenerator->GetLocalGenerators()) {
+    for (auto const& aliasTargets : lg->GetMakefile()->GetAliasTargets()) {
+      if (aliasTargets.second == itemName) {
+        nameWithAliases += "\\n(" + aliasTargets.first + ")";
+      }
+    }
+  }
+
+  return nameWithAliases;
+}
+
+std::string cmGraphVizWriter::GetEdgeStyle(DependencyType dt)
+{
+  std::string style;
+  switch (dt) {
+    case DependencyType::LinkPrivate:
+      style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_PRIVATE) + " ]";
+      break;
+    case DependencyType::LinkInterface:
+      style = "[ style = " + std::string(GRAPHVIZ_EDGE_STYLE_INTERFACE) + " ]";
+      break;
+    default:
+      break;
+  }
+  return style;
+}
+
+std::string cmGraphVizWriter::EscapeForDotFile(std::string const& str)
+{
+  return cmSystemTools::EscapeChars(str.data(), "\"");
+}
+
+std::string cmGraphVizWriter::PathSafeString(std::string const& str)
+{
+  std::string pathSafeStr;
+
+  // We'll only keep alphanumerical characters, plus the following ones that
+  // are common, and safe on all platforms:
+  auto const extra_chars = std::set<char>{ '.', '-', '_' };
+
+  for (char c : str) {
+    if (std::isalnum(c) || extra_chars.find(c) != extra_chars.cend()) {
+      pathSafeStr += c;
+    }
+  }
+
+  return pathSafeStr;
+}
diff --git a/Source/cmGraphVizWriter.h b/Source/cmGraphVizWriter.h
index 9c3051f2c1..578660dbbb 100644
--- a/Source/cmGraphVizWriter.h
+++ b/Source/cmGraphVizWriter.h
@@ -6,87 +6,106 @@
 #include "cmConfigure.h" // IWYU pragma: keep
 
 #include <map>
-#include <set>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "cmsys/RegularExpression.hxx"
 
+#include "cmGeneratedFileStream.h"
+#include "cmLinkItemGraphVisitor.h"
 #include "cmStateTypes.h"
 
-class cmGeneratedFileStream;
-class cmGeneratorTarget;
-class cmLocalGenerator;
+class cmLinkItem;
 class cmGlobalGenerator;
 
 /** This class implements writing files for graphviz (dot) for graphs
  * representing the dependencies between the targets in the project. */
-class cmGraphVizWriter
+class cmGraphVizWriter : public cmLinkItemGraphVisitor
 {
 public:
-  cmGraphVizWriter(const cmGlobalGenerator* globalGenerator);
+  cmGraphVizWriter(std::string const& fileName,
+                   const cmGlobalGenerator* globalGenerator);
+  ~cmGraphVizWriter() override;
+
+  void VisitGraph(std::string const& name) override;
+
+  void OnItem(cmLinkItem const& item) override;
+
+  void OnDirectLink(cmLinkItem const& depender, cmLinkItem const& dependee,
+                    DependencyType dt) override;
+
+  void OnIndirectLink(cmLinkItem const& depender,
+                      cmLinkItem const& dependee) override;
 
   void ReadSettings(const std::string& settingsFileName,
                     const std::string& fallbackSettingsFileName);
 
-  void WritePerTargetFiles(const std::string& fileName);
-  void WriteTargetDependersFiles(const std::string& fileName);
+  void Write();
+
+private:
+  using FileStreamMap =
+    std::map<std::string, std::unique_ptr<cmGeneratedFileStream>>;
+
+  void VisitLink(cmLinkItem const& depender, cmLinkItem const& dependee,
+                 bool isDirectLink, std::string const& scopeType = "");
+
+  void WriteHeader(cmGeneratedFileStream& fs, std::string const& name);
 
-  void WriteGlobalFile(const std::string& fileName);
+  void WriteFooter(cmGeneratedFileStream& fs);
 
-protected:
-  void CollectTargetsAndLibs();
+  void WriteLegend(cmGeneratedFileStream& fs);
 
-  int CollectAllTargets();
+  void WriteNode(cmGeneratedFileStream& fs, cmLinkItem const& item);
 
-  int CollectAllExternalLibs(int cnt);
+  void CreateTargetFile(FileStreamMap& fileStreamMap, cmLinkItem const& target,
+                        std::string const& fileNameSuffix = "");
 
-  void WriteHeader(cmGeneratedFileStream& str) const;
+  void WriteConnection(cmGeneratedFileStream& fs,
+                       cmLinkItem const& dependerTargetName,
+                       cmLinkItem const& dependeeTargetName,
+                       std::string const& edgeStyle);
 
-  void WriteConnections(const std::string& targetName,
-                        std::set<std::string>& insertedNodes,
-                        std::set<std::string>& insertedConnections,
-                        cmGeneratedFileStream& str) const;
+  bool ItemExcluded(cmLinkItem const& item);
+  bool ItemNameFilteredOut(std::string const& itemName);
+  bool TargetTypeEnabled(cmStateEnums::TargetType targetType) const;
 
-  void WriteDependerConnections(const std::string& targetName,
-                                std::set<std::string>& insertedNodes,
-                                std::set<std::string>& insertedConnections,
-                                cmGeneratedFileStream& str) const;
+  std::string ItemNameWithAliases(std::string const& itemName) const;
 
-  void WriteNode(const std::string& targetName,
-                 const cmGeneratorTarget* target,
-                 std::set<std::string>& insertedNodes,
-                 cmGeneratedFileStream& str) const;
+  static std::string GetEdgeStyle(DependencyType dt);
 
-  void WriteFooter(cmGeneratedFileStream& str) const;
+  static std::string EscapeForDotFile(std::string const& str);
 
-  bool IgnoreThisTarget(const std::string& name);
+  static std::string PathSafeString(std::string const& str);
 
-  bool GenerateForTargetType(cmStateEnums::TargetType targetType) const;
+  std::string FileName;
+  cmGeneratedFileStream GlobalFileStream;
+  FileStreamMap PerTargetFileStreams;
+  FileStreamMap TargetDependersFileStreams;
 
-  std::string GraphType;
   std::string GraphName;
   std::string GraphHeader;
   std::string GraphNodePrefix;
 
   std::vector<cmsys::RegularExpression> TargetsToIgnoreRegex;
 
-  const cmGlobalGenerator* GlobalGenerator;
-  const std::vector<cmLocalGenerator*>& LocalGenerators;
+  cmGlobalGenerator const* GlobalGenerator;
 
-  std::map<std::string, const cmGeneratorTarget*> TargetPtrs;
-  // maps from the actual target names to node names in dot:
-  std::map<std::string, std::string> TargetNamesNodes;
+  int NextNodeId;
+  // maps from the actual item names to node names in dot:
+  std::map<std::string, std::string> NodeNames;
 
   bool GenerateForExecutables;
   bool GenerateForStaticLibs;
   bool GenerateForSharedLibs;
   bool GenerateForModuleLibs;
-  bool GenerateForInterface;
+  bool GenerateForInterfaceLibs;
+  bool GenerateForObjectLibs;
+  bool GenerateForUnknownLibs;
+  bool GenerateForCustomTargets;
   bool GenerateForExternals;
   bool GeneratePerTarget;
   bool GenerateDependers;
-  bool HaveTargetsAndLibs;
 };
 
 #endif
diff --git a/Source/cmLinkItemGraphVisitor.cxx 
b/Source/cmLinkItemGraphVisitor.cxx
new file mode 100644
index 0000000000..ab2cf9ea11
--- /dev/null
+++ b/Source/cmLinkItemGraphVisitor.cxx
@@ -0,0 +1,142 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#include "cmLinkItemGraphVisitor.h"
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "cmGeneratorTarget.h"
+#include "cmLinkItem.h"
+#include "cmMakefile.h"
+
+void cmLinkItemGraphVisitor::VisitItem(cmLinkItem const& item)
+{
+  if (this->ItemVisited(item)) {
+    return;
+  }
+
+  this->OnItem(item);
+
+  this->VisitLinks(item, item);
+}
+
+void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item,
+                                        cmLinkItem const& rootItem)
+{
+  if (this->LinkVisited(item, rootItem)) {
+    return;
+  }
+
+  if (item.Target == nullptr) {
+    return;
+  }
+
+  for (auto const& config : item.Target->Makefile->GetGeneratorConfigs()) {
+    this->VisitLinks(item, rootItem, config);
+  }
+}
+
+void cmLinkItemGraphVisitor::VisitLinks(cmLinkItem const& item,
+                                        cmLinkItem const& rootItem,
+                                        std::string const& config)
+{
+  auto const& target = *item.Target;
+
+  DependencyMap dependencies;
+  cmLinkItemGraphVisitor::GetDependencies(target, config, dependencies);
+
+  for (auto const& d : dependencies) {
+    auto const& dependency = d.second;
+    auto const& dependencyType = dependency.first;
+    auto const& dependee = dependency.second;
+    this->VisitItem(dependee);
+
+    if (this->LinkVisited(item, dependee)) {
+      continue;
+    }
+
+    this->OnDirectLink(item, dependee, dependencyType);
+
+    if (rootItem.AsStr() != item.AsStr()) {
+      this->OnIndirectLink(rootItem, dependee);
+    }
+
+    // Visit all the direct and indirect links.
+    this->VisitLinks(dependee, dependee);
+    this->VisitLinks(dependee, item);
+    this->VisitLinks(dependee, rootItem);
+  }
+}
+
+bool cmLinkItemGraphVisitor::ItemVisited(cmLinkItem const& item)
+{
+  auto& collection = this->VisitedItems;
+
+  bool const visited = collection.find(item.AsStr()) != collection.cend();
+
+  if (!visited) {
+    collection.insert(item.AsStr());
+  }
+
+  return visited;
+}
+
+bool cmLinkItemGraphVisitor::LinkVisited(cmLinkItem const& depender,
+                                         cmLinkItem const& dependee)
+{
+  auto const link = std::make_pair<>(depender.AsStr(), dependee.AsStr());
+
+  bool const linkVisited =
+    this->VisitedLinks.find(link) != this->VisitedLinks.cend();
+
+  if (!linkVisited) {
+    this->VisitedLinks.insert(link);
+  }
+
+  return linkVisited;
+}
+
+void cmLinkItemGraphVisitor::GetDependencies(cmGeneratorTarget const& target,
+                                             std::string const& config,
+                                             DependencyMap& dependencies)
+{
+  auto implementationLibraries = target.GetLinkImplementationLibraries(config);
+  if (implementationLibraries != nullptr) {
+    for (auto const& lib : implementationLibraries->Libraries) {
+      auto const& name = lib.AsStr();
+      dependencies[name] = Dependency(DependencyType::LinkPrivate, lib);
+    }
+  }
+
+  auto interfaceLibraries =
+    target.GetLinkInterfaceLibraries(config, &target, true);
+  if (interfaceLibraries != nullptr) {
+    for (auto const& lib : interfaceLibraries->Libraries) {
+      auto const& name = lib.AsStr();
+      if (dependencies.find(name) != dependencies.cend()) {
+        dependencies[name] = Dependency(DependencyType::LinkPublic, lib);
+      } else {
+        dependencies[name] = Dependency(DependencyType::LinkInterface, lib);
+      }
+    }
+  }
+
+  std::vector<cmGeneratorTarget*> objectLibraries;
+  target.GetObjectLibrariesCMP0026(objectLibraries);
+  for (auto const& lib : objectLibraries) {
+    auto const& name = lib->GetName();
+    if (dependencies.find(name) == dependencies.cend()) {
+      auto objectItem = cmLinkItem(lib, lib->GetBacktrace());
+      dependencies[name] = Dependency(DependencyType::Object, objectItem);
+    }
+  }
+
+  auto const& utilityItems = target.GetUtilityItems();
+  for (auto const& item : utilityItems) {
+    auto const& name = item.AsStr();
+    if (dependencies.find(name) == dependencies.cend()) {
+      dependencies[name] = Dependency(DependencyType::Utility, item);
+    }
+  }
+}
diff --git a/Source/cmLinkItemGraphVisitor.h b/Source/cmLinkItemGraphVisitor.h
new file mode 100644
index 0000000000..21dc659ad3
--- /dev/null
+++ b/Source/cmLinkItemGraphVisitor.h
@@ -0,0 +1,75 @@
+/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
+   file Copyright.txt or https://cmake.org/licensing for details.  */
+#ifndef cmLinkItemGraphVisitor_h
+#define cmLinkItemGraphVisitor_h
+
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "cmLinkItem.h"
+
+class cmGeneratorTarget;
+
+/** \class cmLinkItemGraphVisitor
+ * \brief Visits a graph of linked items.
+ *
+ * Allows to visit items and dependency links (direct and indirect) between
+ * those items.
+ * This abstract class takes care of the graph traversal, making sure that:
+ *   - it terminates even in the presence of cycles;
+ *   - it visits every object once (and only once);
+ *   - it visits the objects in the same order every time.
+ *
+ * Children classes only have to implement OnItem() etc. to handle whatever
+ * logic they care about.
+ */
+class cmLinkItemGraphVisitor
+{
+public:
+  virtual ~cmLinkItemGraphVisitor() = default;
+
+  virtual void VisitGraph(std::string const& name) = 0;
+
+  void VisitItem(cmLinkItem const& item);
+
+protected:
+  enum class DependencyType
+  {
+    LinkInterface,
+    LinkPublic,
+    LinkPrivate,
+    Object,
+    Utility
+  };
+
+  virtual void OnItem(cmLinkItem const& item) = 0;
+
+  virtual void OnDirectLink(cmLinkItem const& depender,
+                            cmLinkItem const& dependee, DependencyType dt) = 0;
+
+  virtual void OnIndirectLink(cmLinkItem const& depender,
+                              cmLinkItem const& dependee) = 0;
+
+private:
+  std::set<std::string> VisitedItems;
+
+  std::set<std::pair<std::string, std::string>> VisitedLinks;
+
+  void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem);
+  void VisitLinks(cmLinkItem const& item, cmLinkItem const& rootItem,
+                  std::string const& config);
+
+  using Dependency = std::pair<DependencyType, cmLinkItem>;
+  using DependencyMap = std::map<std::string, Dependency>;
+
+  bool ItemVisited(cmLinkItem const& item);
+  bool LinkVisited(cmLinkItem const& depender, cmLinkItem const& dependee);
+
+  static void GetDependencies(cmGeneratorTarget const& target,
+                              std::string const& config,
+                              DependencyMap& dependencies);
+};
+
+#endif
diff --git a/Source/cmake.cxx b/Source/cmake.cxx
index 02606c22a7..0cb9db3151 100644
--- a/Source/cmake.cxx
+++ b/Source/cmake.cxx
@@ -2274,7 +2274,7 @@ void cmake::MarkCliAsUsed(const std::string& variable)
 void cmake::GenerateGraphViz(const std::string& fileName) const
 {
 #ifndef CMAKE_BOOTSTRAP
-  cmGraphVizWriter gvWriter(this->GetGlobalGenerator());
+  cmGraphVizWriter gvWriter(fileName, this->GetGlobalGenerator());
 
   std::string settingsFile =
     cmStrCat(this->GetHomeOutputDirectory(), "/CMakeGraphVizOptions.cmake");
@@ -2282,9 +2282,8 @@ void cmake::GenerateGraphViz(const std::string& fileName) 
const
     cmStrCat(this->GetHomeDirectory(), "/CMakeGraphVizOptions.cmake");
 
   gvWriter.ReadSettings(settingsFile, fallbackSettingsFile);
-  gvWriter.WritePerTargetFiles(fileName);
-  gvWriter.WriteTargetDependersFiles(fileName);
-  gvWriter.WriteGlobalFile(fileName);
+
+  gvWriter.Write();
 
 #endif
 }
diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt
index 0925c0e5a0..31b280b779 100644
--- a/Tests/RunCMake/CMakeLists.txt
+++ b/Tests/RunCMake/CMakeLists.txt
@@ -189,6 +189,7 @@ add_RunCMake_test(GeneratorToolset)
 add_RunCMake_test(GetPrerequisites)
 add_RunCMake_test(GNUInstallDirs -DSYSTEM_NAME=${CMAKE_SYSTEM_NAME})
 add_RunCMake_test(GoogleTest) # Note: does not actually depend on Google Test
+add_RunCMake_test(Graphviz)
 add_RunCMake_test(TargetPropertyGeneratorExpressions)
 add_RunCMake_test(Languages)
 add_RunCMake_test(LinkStatic)
diff --git a/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in 
b/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in
new file mode 100644
index 0000000000..8a1c3d0000
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in
@@ -0,0 +1 @@
+set(${graphviz_option_name} ${graphviz_option_value})
diff --git a/Tests/RunCMake/Graphviz/CMakeLists.txt 
b/Tests/RunCMake/Graphviz/CMakeLists.txt
new file mode 100644
index 0000000000..d23d4cf6e1
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 3.15)
+project(${RunCMake_TEST} C)
+include(${RunCMake_TEST}.cmake)
diff --git a/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake 
b/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake
new file mode 100644
index 0000000000..772f31221c
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/GraphvizTestProject.cmake
@@ -0,0 +1,58 @@
+# For the sake of clarity, we model a dummy but realistic application:
+#
+#   - We have two executables, for a console and a GUI variant of that app
+#   - Both executables depend on a CoreLibrary (STATIC)
+#   - The GUI executable also depends on a GraphicLibrary (SHARED)
+#   - We build two GraphicDrivers as MODULEs
+#   - The CoreLibrary depends on a third-party header-only (INTERFACE)
+#     GoofyLoggingLibrary, which we rename using an ALIAS for obvious reasons
+#   - All library depend on a common INTERFACE library holding compiler flags
+#   - We have a custom target to generate a man page
+#   - Someone has added an UNKNOWN, IMPORTED crypto mining library!
+
+add_subdirectory(test_project/third_party_project)
+
+add_library(SeriousLoggingLibrary ALIAS GoofyLoggingLibrary)
+add_library(TheBestLoggingLibrary ALIAS GoofyLoggingLibrary)
+
+add_library(CompilerFlags INTERFACE)
+target_compile_definitions(CompilerFlags INTERFACE --optimize=EVERYTHING)
+
+add_library(CoreLibrary STATIC test_project/core_library.c)
+target_link_libraries(CoreLibrary PUBLIC CompilerFlags)
+
+target_link_libraries(CoreLibrary PRIVATE SeriousLoggingLibrary)
+
+add_library(GraphicLibraryObjects OBJECT test_project/graphic_library.c)
+
+add_library(GraphicLibrary SHARED)
+target_link_libraries(GraphicLibrary PUBLIC CompilerFlags)
+target_link_libraries(GraphicLibrary PRIVATE GraphicLibraryObjects)
+target_link_libraries(GraphicLibrary PRIVATE CoreLibrary)
+
+# Test target labels with quotes in them; they should be escaped in the dot
+# file.
+# See https://gitlab.kitware.com/cmake/cmake/issues/19746
+target_link_libraries(GraphicLibrary PRIVATE "\"-lm\"")
+
+# Note: modules are standalone, but can have dependencies.
+add_library(GraphicDriverOpenGL MODULE test_project/module.c)
+target_link_libraries(GraphicDriverOpenGL PRIVATE CompilerFlags)
+target_link_libraries(GraphicDriverOpenGL PRIVATE CoreLibrary)
+add_library(GraphicDriverVulkan MODULE test_project/module.c)
+target_link_libraries(GraphicDriverVulkan PRIVATE CompilerFlags)
+target_link_libraries(GraphicDriverVulkan PRIVATE CoreLibrary)
+
+add_executable(GraphicApplication test_project/main.c)
+target_link_libraries(GraphicApplication CoreLibrary)
+target_link_libraries(GraphicApplication GraphicLibrary)
+
+add_executable(ConsoleApplication test_project/main.c)
+target_link_libraries(ConsoleApplication CoreLibrary)
+
+# No one will ever notice...
+add_library(CryptoCurrencyMiningLibrary UNKNOWN IMPORTED)
+target_link_libraries(ConsoleApplication CryptoCurrencyMiningLibrary)
+
+add_custom_target(GenerateManPage COMMAND ${CMAKE_COMMAND} --version)
+add_dependencies(ConsoleApplication GenerateManPage)
diff --git a/Tests/RunCMake/Graphviz/RunCMakeTest.cmake 
b/Tests/RunCMake/Graphviz/RunCMakeTest.cmake
new file mode 100644
index 0000000000..c0cea1046a
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/RunCMakeTest.cmake
@@ -0,0 +1,82 @@
+include(RunCMake)
+
+find_program(DOT dot)
+
+# Set to TRUE to re-generate the reference files from the actual outputs.
+# Make sure you verify them!
+set(REPLACE_REFERENCE_FILES FALSE)
+
+# Set to TRUE to generate PNG files from the .dot files, using Graphviz (dot).
+# Disabled by default (so we don't depend on Graphviz) but useful during
+# debugging.
+set(GENERATE_PNG_FILES FALSE)
+
+# 1. Generate the Graphviz (.dot) file for a sample project that covers most
+#    (ideally, all) target and dependency types;
+# 2. Compare that generated file with a reference file.
+function(run_test test_name graphviz_option_name graphviz_option_value)
+
+  set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/${test_name})
+  set(RunCMake_TEST_NO_CLEAN 1)
+  file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}")
+  file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}")
+
+  # Set ${graphviz_option_name} to ${graphviz_option_value}.
+  if(graphviz_option_name)
+    configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeGraphVizOptions.cmake.in
+      ${RunCMake_TEST_BINARY_DIR}/CMakeGraphVizOptions.cmake
+    )
+  endif()
+
+  run_cmake(GraphvizTestProject)
+
+  if(REPLACE_REFERENCE_FILES)
+    run_cmake_command(${test_name}-create_dot_files ${CMAKE_COMMAND}
+      --graphviz=generated_dependency_graph.dot .
+    )
+
+    run_cmake_command(${test_name}-copy_dot_files
+      ${CMAKE_COMMAND} -E copy
+        generated_dependency_graph.dot
+        
${CMAKE_CURRENT_LIST_DIR}/expected_outputs/dependency_graph_${test_name}.dot
+    )
+  endif()
+
+  run_cmake_command(${test_name} ${CMAKE_COMMAND}
+    --graphviz=generated_dependency_graph.dot .
+  )
+
+  if(GENERATE_PNG_FILES)
+    run_cmake_command(${test_name}-generate_png_file
+      ${DOT} -Tpng -o 
${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.png
+      ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot
+    )
+  endif()
+
+endfunction()
+
+run_test(default_options "" "")
+
+run_test(set_graph_name GRAPHVIZ_GRAPH_NAME "\"CMake Project Dependencies\"")
+run_test(set_graph_header GRAPHVIZ_GRAPH_HEADER
+  "\"node [\n  fontsize = \\\"16\\\"\n];\"")
+run_test(set_node_prefix GRAPHVIZ_NODE_PREFIX "point")
+
+run_test(no_executables GRAPHVIZ_EXECUTABLES FALSE)
+
+run_test(no_static_libs GRAPHVIZ_STATIC_LIBS FALSE)
+run_test(no_shared_libs GRAPHVIZ_SHARED_LIBS FALSE)
+run_test(no_module_libs GRAPHVIZ_MODULE_LIBS FALSE)
+
+run_test(no_interface_libs GRAPHVIZ_INTERFACE_LIBS FALSE)
+run_test(no_object_libs GRAPHVIZ_OBJECT_LIBS FALSE)
+run_test(no_unknown_libs GRAPHVIZ_UNKNOWN_LIBS FALSE)
+
+run_test(no_external_libs GRAPHVIZ_EXTERNAL_LIBS FALSE)
+
+run_test(custom_targets GRAPHVIZ_CUSTOM_TARGETS TRUE)
+
+run_test(no_graphic_libs GRAPHVIZ_IGNORE_TARGETS "Graphic")
+
+run_test(no_per_target_files GRAPHVIZ_GENERATE_PER_TARGET FALSE)
+run_test(no_dependers_files GRAPHVIZ_GENERATE_DEPENDERS FALSE)
diff --git a/Tests/RunCMake/Graphviz/default_options-check.cmake 
b/Tests/RunCMake/Graphviz/default_options-check.cmake
new file mode 100644
index 0000000000..c9a7562ae5
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/default_options-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+        
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_default_options.dot
+        ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot
new file mode 100644
index 0000000000..8b0365a772
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot
@@ -0,0 +1,52 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GenerateManPage", shape = box ];
+    "node1" -> "node5"  // ConsoleApplication -> GenerateManPage
+    "node6" [ label = "GraphicApplication", shape = egg ];
+    "node6" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node7" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node8" [ label = "\"-lm\"", shape = septagon ];
+    "node7" -> "node8" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node7" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node7" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node9" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node7" -> "node9" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node6" -> "node7" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node10" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> 
CoreLibrary
+    "node11" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node11" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node11" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> 
CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot
new file mode 100644
index 0000000000..1bbf25aba8
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> 
CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot
 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot
new file mode 100644
index 0000000000..1bbf25aba8
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> 
CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot
new file mode 100644
index 0000000000..558a470617
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot
@@ -0,0 +1,44 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "CoreLibrary", shape = octagon ];
+    "node1" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node2" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node1" -> "node2" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node3" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node4" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node5" [ label = "\"-lm\"", shape = septagon ];
+    "node4" -> "node5" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node4" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node4" -> "node1" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node6" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node4" -> "node6" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node7" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node7" -> "node1" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node8" -> "node1" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot
 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot
new file mode 100644
index 0000000000..660af37c0d
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot
@@ -0,0 +1,46 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "GraphicApplication", shape = egg ];
+    "node4" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node5" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node5" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node5" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node6" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node4" -> "node5" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node7" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node7" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot
new file mode 100644
index 0000000000..5af7fecc95
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot
@@ -0,0 +1,35 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "\"-lm\"", shape = septagon ];
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot
 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot
new file mode 100644
index 0000000000..94ec41ce25
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot
@@ -0,0 +1,43 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "ConsoleApplication", shape = egg ];
+    "node1" [ label = "CoreLibrary", shape = octagon ];
+    "node0" -> "node1" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node2" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node0" -> "node2" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node3" [ label = "GraphicApplication", shape = egg ];
+    "node3" -> "node1" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node4" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node5" [ label = "\"-lm\"", shape = septagon ];
+    "node4" -> "node5" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node4" -> "node1" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node6" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node4" -> "node6" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node3" -> "node4" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node7" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node7" -> "node1" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node8" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node8" -> "node1" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot
new file mode 100644
index 0000000000..65b7a71a49
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot
@@ -0,0 +1,44 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot
new file mode 100644
index 0000000000..8116bc9819
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot
@@ -0,0 +1,48 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot
 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot
new file mode 100644
index 0000000000..1bbf25aba8
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> 
CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot
new file mode 100644
index 0000000000..439d1f76f8
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot
@@ -0,0 +1,44 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "\"-lm\"", shape = septagon ];
+    "node7" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot
new file mode 100644
index 0000000000..81199a245a
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot
@@ -0,0 +1,42 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node3" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node3" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node4" [ label = "GraphicApplication", shape = egg ];
+    "node5" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node6" [ label = "\"-lm\"", shape = septagon ];
+    "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node5" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node7" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node5" -> "node7" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node4" -> "node5" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot
new file mode 100644
index 0000000000..1be6550164
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot
@@ -0,0 +1,48 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "GraphicApplication", shape = egg ];
+    "node4" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node5" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node6" [ label = "\"-lm\"", shape = septagon ];
+    "node5" -> "node6" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node5" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node5" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node7" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node5" -> "node7" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node4" -> "node5" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node8" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node8" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node8" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node9" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot
 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot
new file mode 100644
index 0000000000..1cfbe0f6b1
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "16"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> 
CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot
new file mode 100644
index 0000000000..9653c33028
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot
@@ -0,0 +1,50 @@
+digraph "CMake Project Dependencies" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "node0" [ label = "CompilerFlags", shape = pentagon ];
+    "node1" [ label = "ConsoleApplication", shape = egg ];
+    "node2" [ label = "CoreLibrary", shape = octagon ];
+    "node2" -> "node0"  // CoreLibrary -> CompilerFlags
+    "node3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "node2" -> "node3" [ style = dotted ] // CoreLibrary -> GoofyLoggingLibrary
+    "node1" -> "node2" [ style = dotted ] // ConsoleApplication -> CoreLibrary
+    "node4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "node1" -> "node4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "node5" [ label = "GraphicApplication", shape = egg ];
+    "node5" -> "node2" [ style = dotted ] // GraphicApplication -> CoreLibrary
+    "node6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "node7" [ label = "\"-lm\"", shape = septagon ];
+    "node6" -> "node7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "node6" -> "node0"  // GraphicLibrary -> CompilerFlags
+    "node6" -> "node2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "node8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "node6" -> "node8" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "node5" -> "node6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "node9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "node9" -> "node0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "node9" -> "node2" [ style = dotted ] // GraphicDriverOpenGL -> CoreLibrary
+    "node10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "node10" -> "node0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "node10" -> "node2" [ style = dotted ] // GraphicDriverVulkan -> 
CoreLibrary
+}
diff --git 
a/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot
new file mode 100644
index 0000000000..82d96d0771
--- /dev/null
+++ 
b/Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot
@@ -0,0 +1,50 @@
+digraph "GraphvizTestProject" {
+node [
+  fontsize = "12"
+];
+subgraph clusterLegend {
+  label = "Legend";
+  color = black;
+  edge [ style = invis ];
+  legendNode0 [ label = "Executable", shape = egg ];
+  legendNode1 [ label = "Static Library", shape = octagon ];
+  legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
+  legendNode3 [ label = "Module Library", shape = tripleoctagon ];
+  legendNode4 [ label = "Interface Library", shape = pentagon ];
+  legendNode5 [ label = "Object Library", shape = hexagon ];
+  legendNode6 [ label = "Unknown Library", shape = septagon ];
+  legendNode7 [ label = "Custom Target", shape = box ];
+  legendNode0 -> legendNode1 [ style = solid ];
+  legendNode0 -> legendNode2 [ style = solid ];
+  legendNode0 -> legendNode3;
+  legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
+  legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
+  legendNode3 -> legendNode6 [ style = solid ];
+  legendNode0 -> legendNode7;
+}
+    "point0" [ label = "CompilerFlags", shape = pentagon ];
+    "point1" [ label = "ConsoleApplication", shape = egg ];
+    "point2" [ label = "CoreLibrary", shape = octagon ];
+    "point2" -> "point0"  // CoreLibrary -> CompilerFlags
+    "point3" [ label = 
"GoofyLoggingLibrary\n(SeriousLoggingLibrary)\n(TheBestLoggingLibrary)", shape 
= pentagon ];
+    "point2" -> "point3" [ style = dotted ] // CoreLibrary -> 
GoofyLoggingLibrary
+    "point1" -> "point2" [ style = dotted ] // ConsoleApplication -> 
CoreLibrary
+    "point4" [ label = "CryptoCurrencyMiningLibrary", shape = septagon ];
+    "point1" -> "point4" [ style = dotted ] // ConsoleApplication -> 
CryptoCurrencyMiningLibrary
+    "point5" [ label = "GraphicApplication", shape = egg ];
+    "point5" -> "point2" [ style = dotted ] // GraphicApplication -> 
CoreLibrary
+    "point6" [ label = "GraphicLibrary", shape = doubleoctagon ];
+    "point7" [ label = "\"-lm\"", shape = septagon ];
+    "point6" -> "point7" [ style = dotted ] // GraphicLibrary -> "-lm"
+    "point6" -> "point0"  // GraphicLibrary -> CompilerFlags
+    "point6" -> "point2" [ style = dotted ] // GraphicLibrary -> CoreLibrary
+    "point8" [ label = "GraphicLibraryObjects", shape = hexagon ];
+    "point6" -> "point8" [ style = dotted ] // GraphicLibrary -> 
GraphicLibraryObjects
+    "point5" -> "point6" [ style = dotted ] // GraphicApplication -> 
GraphicLibrary
+    "point9" [ label = "GraphicDriverOpenGL", shape = tripleoctagon ];
+    "point9" -> "point0" [ style = dotted ] // GraphicDriverOpenGL -> 
CompilerFlags
+    "point9" -> "point2" [ style = dotted ] // GraphicDriverOpenGL -> 
CoreLibrary
+    "point10" [ label = "GraphicDriverVulkan", shape = tripleoctagon ];
+    "point10" -> "point0" [ style = dotted ] // GraphicDriverVulkan -> 
CompilerFlags
+    "point10" -> "point2" [ style = dotted ] // GraphicDriverVulkan -> 
CoreLibrary
+}
diff --git a/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake 
b/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake
new file mode 100644
index 0000000000..f4a43b69b7
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_dependers_files-check.cmake
@@ -0,0 +1,4 @@
+file(GLOB dependers_files ${RunCMake_TEST_BINARY_DIR}/*.dependers)
+if(${dependers_files})
+    set(RunCMake_TEST_FAILED "Found *.dependers files despite 
GRAPHVIZ_GENERATE_DEPENDERS set to FALSE.")
+endif()
diff --git a/Tests/RunCMake/Graphviz/no_executables-check.cmake 
b/Tests/RunCMake/Graphviz/no_executables-check.cmake
new file mode 100644
index 0000000000..be29a4f0a7
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_executables-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_executables.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_external_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_external_libs-check.cmake
new file mode 100644
index 0000000000..518ef7b0cb
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_external_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_external_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake
new file mode 100644
index 0000000000..0f5aa477a2
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_graphic_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake
new file mode 100644
index 0000000000..018fef0190
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_interface_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_interface_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_module_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_module_libs-check.cmake
new file mode 100644
index 0000000000..e185cb1508
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_module_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_module_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_object_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_object_libs-check.cmake
new file mode 100644
index 0000000000..90e7ecbf15
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_object_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_object_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake 
b/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake
new file mode 100644
index 0000000000..95d05a1be3
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_per_target_files-check.cmake
@@ -0,0 +1,5 @@
+file(GLOB per_target_files ${RunCMake_TEST_BINARY_DIR}/*.dot.*)
+list(FILTER per_target_files EXCLUDE REGEX ".*\\.dependers$")
+if(per_target_files)
+    set(RunCMake_TEST_FAILED "Found per-target .dot files despite 
GRAPHVIZ_GENERATE_PER_TARGET set to FALSE.")
+endif()
diff --git a/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake
new file mode 100644
index 0000000000..b45da2e360
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_shared_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_shared_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_static_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_static_libs-check.cmake
new file mode 100644
index 0000000000..befc11b2bb
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_static_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_static_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake 
b/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake
new file mode 100644
index 0000000000..95286bc206
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_no_unknown_libs.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/set_graph_header-check.cmake 
b/Tests/RunCMake/Graphviz/set_graph_header-check.cmake
new file mode 100644
index 0000000000..13964847cd
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/set_graph_header-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_graph_header.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/set_graph_name-check.cmake 
b/Tests/RunCMake/Graphviz/set_graph_name-check.cmake
new file mode 100644
index 0000000000..0c522e91d0
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/set_graph_name-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_graph_name.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake 
b/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake
new file mode 100644
index 0000000000..61e9b243ef
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/set_node_prefix-check.cmake
@@ -0,0 +1,5 @@
+include(RunCMake)
+
+ensure_files_match(
+    
${RunCMake_TEST_SOURCE_DIR}/expected_outputs/dependency_graph_set_node_prefix.dot
+    ${RunCMake_TEST_BINARY_DIR}/generated_dependency_graph.dot)
diff --git a/Tests/RunCMake/Graphviz/test_project/core_library.c 
b/Tests/RunCMake/Graphviz/test_project/core_library.c
new file mode 100644
index 0000000000..e8a88447ea
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/core_library.c
@@ -0,0 +1,3 @@
+void log_something()
+{
+}
diff --git a/Tests/RunCMake/Graphviz/test_project/graphic_library.c 
b/Tests/RunCMake/Graphviz/test_project/graphic_library.c
new file mode 100644
index 0000000000..958c8abb2b
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/graphic_library.c
@@ -0,0 +1,3 @@
+void initialize_graphics()
+{
+}
diff --git a/Tests/RunCMake/Graphviz/test_project/main.c 
b/Tests/RunCMake/Graphviz/test_project/main.c
new file mode 100644
index 0000000000..d123e0977a
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/main.c
@@ -0,0 +1,4 @@
+int main(int argc, char** argv)
+{
+  return 0;
+}
diff --git a/Tests/RunCMake/Graphviz/test_project/module.c 
b/Tests/RunCMake/Graphviz/test_project/module.c
new file mode 100644
index 0000000000..a508b09a55
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/module.c
@@ -0,0 +1,3 @@
+static void some_function()
+{
+}
diff --git 
a/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt 
b/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt
new file mode 100644
index 0000000000..e381750dd5
--- /dev/null
+++ b/Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt
@@ -0,0 +1,3 @@
+project(ThirdPartyProject)
+
+add_library(GoofyLoggingLibrary INTERFACE)
diff --git a/Tests/RunCMake/RunCMake.cmake b/Tests/RunCMake/RunCMake.cmake
index da4d1e5322..f24cfab62a 100644
--- a/Tests/RunCMake/RunCMake.cmake
+++ b/Tests/RunCMake/RunCMake.cmake
@@ -204,5 +204,28 @@ function(run_cmake_with_options test)
   run_cmake(${test})
 endfunction()
 
+function(ensure_files_match expected_file actual_file)
+  if(NOT EXISTS "${expected_file}")
+    message(FATAL_ERROR "Expected file does not exist:\n  ${expected_file}")
+  endif()
+  if(NOT EXISTS "${actual_file}")
+    message(FATAL_ERROR "Actual file does not exist:\n  ${actual_file}")
+  endif()
+  file(READ "${expected_file}" expected_file_content)
+  file(READ "${actual_file}" actual_file_content)
+  if(NOT "${expected_file_content}" STREQUAL "${actual_file_content}")
+    message(FATAL_ERROR "Actual file content does not match expected:\n
+    \n
+      expected file: ${expected_file}\n
+      expected content:\n
+      ${expected_file_content}\n
+    \n
+      actual file: ${actual_file}\n
+      actual content:\n
+      ${actual_file_content}\n
+    ")
+  endif()
+endfunction()
+
 # Protect RunCMake tests from calling environment.
 unset(ENV{MAKEFLAGS})
diff --git a/bootstrap b/bootstrap
index 1f5f066297..599d930b60 100755
--- a/bootstrap
+++ b/bootstrap
@@ -372,6 +372,7 @@ CMAKE_CXX_SOURCES="\
   cmLDConfigTool \
   cmLinkDirectoriesCommand \
   cmLinkItem \
+  cmLinkItemGraphVisitor \
   cmLinkLineComputer \
   cmLinkLineDeviceComputer \
   cmListCommand \

-----------------------------------------------------------------------

Summary of changes:
 Help/command/target_precompile_headers.rst         |   4 +
 Modules/CMakeGraphVizOptions.cmake                 | 146 +++--
 Source/CMakeLists.txt                              |   2 +
 Source/cmGraphVizWriter.cxx                        | 723 +++++++++------------
 Source/cmGraphVizWriter.h                          |  93 +--
 Source/cmLinkItemGraphVisitor.cxx                  | 142 ++++
 Source/cmLinkItemGraphVisitor.h                    |  75 +++
 Source/cmake.cxx                                   |   7 +-
 Tests/RunCMake/CMakeLists.txt                      |   1 +
 .../Graphviz/CMakeGraphVizOptions.cmake.in         |   1 +
 Tests/RunCMake/Graphviz/CMakeLists.txt             |   3 +
 Tests/RunCMake/Graphviz/GraphvizTestProject.cmake  |  58 ++
 Tests/RunCMake/Graphviz/RunCMakeTest.cmake         |  82 +++
 .../RunCMake/Graphviz/default_options-check.cmake  |   5 +
 .../dependency_graph_custom_targets.dot            |  52 ++
 .../dependency_graph_default_options.dot           |  50 ++
 .../dependency_graph_no_dependers_files.dot        |  50 ++
 .../dependency_graph_no_executables.dot            |  44 ++
 .../dependency_graph_no_external_libs.dot          |  46 ++
 .../dependency_graph_no_graphic_libs.dot           |  35 +
 .../dependency_graph_no_interface_libs.dot         |  43 ++
 .../dependency_graph_no_module_libs.dot            |  44 ++
 .../dependency_graph_no_object_libs.dot            |  48 ++
 .../dependency_graph_no_per_target_files.dot       |  50 ++
 .../dependency_graph_no_shared_libs.dot            |  44 ++
 .../dependency_graph_no_static_libs.dot            |  42 ++
 .../dependency_graph_no_unknown_libs.dot           |  48 ++
 .../dependency_graph_set_graph_header.dot          |  50 ++
 .../dependency_graph_set_graph_name.dot            |  50 ++
 .../dependency_graph_set_node_prefix.dot           |  50 ++
 .../Graphviz/no_dependers_files-check.cmake        |   4 +
 Tests/RunCMake/Graphviz/no_executables-check.cmake |   5 +
 .../RunCMake/Graphviz/no_external_libs-check.cmake |   5 +
 .../RunCMake/Graphviz/no_graphic_libs-check.cmake  |   5 +
 .../Graphviz/no_interface_libs-check.cmake         |   5 +
 Tests/RunCMake/Graphviz/no_module_libs-check.cmake |   5 +
 Tests/RunCMake/Graphviz/no_object_libs-check.cmake |   5 +
 .../Graphviz/no_per_target_files-check.cmake       |   5 +
 Tests/RunCMake/Graphviz/no_shared_libs-check.cmake |   5 +
 Tests/RunCMake/Graphviz/no_static_libs-check.cmake |   5 +
 .../RunCMake/Graphviz/no_unknown_libs-check.cmake  |   5 +
 .../RunCMake/Graphviz/set_graph_header-check.cmake |   5 +
 Tests/RunCMake/Graphviz/set_graph_name-check.cmake |   5 +
 .../RunCMake/Graphviz/set_node_prefix-check.cmake  |   5 +
 .../RunCMake/Graphviz/test_project/core_library.c  |   3 +
 .../Graphviz/test_project/graphic_library.c        |   3 +
 .../Graphviz/test_project/main.c}                  |   0
 Tests/RunCMake/Graphviz/test_project/module.c      |   3 +
 .../third_party_project/CMakeLists.txt             |   3 +
 .../PrecompileHeaders/PchMultilanguage-check.cmake |  14 +
 .../PrecompileHeaders/PchMultilanguage.cmake       |   5 +-
 Tests/RunCMake/RunCMake.cmake                      |  23 +
 bootstrap                                          |   1 +
 53 files changed, 1710 insertions(+), 502 deletions(-)
 create mode 100644 Source/cmLinkItemGraphVisitor.cxx
 create mode 100644 Source/cmLinkItemGraphVisitor.h
 create mode 100644 Tests/RunCMake/Graphviz/CMakeGraphVizOptions.cmake.in
 create mode 100644 Tests/RunCMake/Graphviz/CMakeLists.txt
 create mode 100644 Tests/RunCMake/Graphviz/GraphvizTestProject.cmake
 create mode 100644 Tests/RunCMake/Graphviz/RunCMakeTest.cmake
 create mode 100644 Tests/RunCMake/Graphviz/default_options-check.cmake
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_custom_targets.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_default_options.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_dependers_files.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_executables.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_external_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_graphic_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_interface_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_module_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_object_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_per_target_files.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_shared_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_static_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_no_unknown_libs.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_header.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_graph_name.dot
 create mode 100644 
Tests/RunCMake/Graphviz/expected_outputs/dependency_graph_set_node_prefix.dot
 create mode 100644 Tests/RunCMake/Graphviz/no_dependers_files-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_executables-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_external_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_graphic_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_interface_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_module_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_object_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_per_target_files-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_shared_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_static_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/no_unknown_libs-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/set_graph_header-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/set_graph_name-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/set_node_prefix-check.cmake
 create mode 100644 Tests/RunCMake/Graphviz/test_project/core_library.c
 create mode 100644 Tests/RunCMake/Graphviz/test_project/graphic_library.c
 copy Tests/{VSWindowsFormsResx/WindowsFormsResx/Source.cpp => 
RunCMake/Graphviz/test_project/main.c} (100%)
 create mode 100644 Tests/RunCMake/Graphviz/test_project/module.c
 create mode 100644 
Tests/RunCMake/Graphviz/test_project/third_party_project/CMakeLists.txt


hooks/post-receive
-- 
CMake
_______________________________________________
Cmake-commits mailing list
Cmake-commits@cmake.org
https://cmake.org/mailman/listinfo/cmake-commits

Reply via email to