Search code examples
cmakegraphviz

Generate dependency graph for custom targets with GRAPHVIZ_CUSTOM_TARGETS=TRUE


(Update with working solution at bottom)

From what I can tell, generating a dependency graph with custom targets is supported as of CMake 3.17. However, when attempting to do so, I get no dependency mapping between my targets and I get this warning:

CMake Warning:
  Manually-specified variables were not used by the project:

    GRAPHVIZ_CUSTOM_TARGETS

I stumbled upon this SO answer, but it hasn't helped much. The next-closest thing I could find was an incomplete Merge Request to support some different use cases.

I'm running this on Windows, but I don't know if that could be the issue.

So, I'm stumped and could use some help before I file an issue against KitWare... since I think I am missing something really obvious. Any help would be so appreciated.

CMakeLists.txt

cmake_minimum_required(VERSION 3.18)

project(
    gviz 
    LANGUAGES NONE
)
add_custom_command(
    OUTPUT foo.txt
    COMMAND cmake --version > foo.txt
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

add_custom_command(
    OUTPUT bar.txt
    COMMAND cmake --version > bar.txt
    DEPENDS foo.txt
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)


add_custom_target(
    foo
    DEPENDS foo.txt
)

add_custom_target(
    bar
    DEPENDS bar.txt
)

Command ran from console, and output:

Console Output:

cmake_graphviz> cmake --graphviz=group.dot -BNBuild -GNinja . -DGRAPHVIZ_CUSTOM_TARGETS=TRUE
-- Configuring done
-- Generating done
Generate graphviz: cmake_graphviz/group.dot
CMake Warning:
  Manually-specified variables were not used by the project:

    GRAPHVIZ_CUSTOM_TARGETS


-- Build files have been written to: cmake_graphviz/NBuild

And finally, the group.dot file:

digraph "gviz" {
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;
}
}

Working solution:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.18)

project(
    gviz 
    LANGUAGES NONE
)

# Because I don't like cmake files flooding my root directory
file(COPY cmake/CMakeGraphVizOptions.cmake DESTINATION ${CMAKE_BINARY_DIR})

add_custom_command(
    OUTPUT foo.txt
    COMMAND cmake --version > foo.txt
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

add_custom_command(
    OUTPUT bar.txt
    COMMAND cmake --version > bar.txt
    DEPENDS foo.txt
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)


add_custom_target(
    foo
    DEPENDS foo.txt
)

add_custom_target(bar)

add_dependencies(bar foo)

cmake/CMakeGraphVizOptions.cmake

# This file sets some options to control GraphViz graphs.
set(GRAPHVIZ_GRAPH_NAME "MyGraph")
set(GRAPHVIZ_CUSTOM_TARGETS TRUE)
set(GRAPHVIZ_NODE_PREFIX "blah")

File List output:

group.dot
group.dot.bar
group.dot.foo
group.dot.bar.dependers
group.dot.bar.dependers

Now, the only issue I have is it doesn't seem to link dependencies via file outputs, but that is outside of the scope of this question :)


Solution

  • In the linked documentation, it states:

    The look and content of the generated graphs can be controlled using the file CMakeGraphVizOptions.cmake. This file is first searched in CMAKE_BINARY_DIR, and then in CMAKE_SOURCE_DIR. If found, the variables set in it are used to adjust options for the generated Graphviz files.

    So, instead of setting GRAPHVIZ_CUSTOM_TARGETS in the cmake command line, set it in a file called CMakeGraphVizOptions.cmake, and add this file to your top-level source directory.

    An example CMakeGraphVizOptions.cmake:

    # This file sets some options to control GraphViz graphs.
    set(GRAPHVIZ_GRAPH_NAME "MyGraph")
    set(GRAPHVIZ_CUSTOM_TARGETS TRUE)