Visualizing CMake Project Dependencies with Graphviz
As C++ projects grow, understanding the web of dependencies between libraries and executables becomes critical for maintenance, build optimization, and architectural decisions. Graphviz provides a straightforward way to visualize your CMake build structure as a dependency graph.
How It Works
CMake can generate .dot files that describe relationships between targets (libraries, executables, and custom targets). These files use Graphviz’s DOT language, a human-readable format for describing directed graphs. You can then convert these files to PNG, SVG, or other formats for inspection.
Generating Dependency Graphs
Basic Setup
CMake’s graphviz support is built-in and requires no additional configuration. Simply run:
cmake --graphviz=project.dot .
This generates project.dot in your build directory, containing the full dependency graph.
Converting to Image Formats
Use the dot command from Graphviz to convert to your preferred format:
# PNG (raster, good for quick sharing)
dot -Tpng project.dot -o project_graph.png
# SVG (vector, zoomable, good for documentation)
dot -Tsvg project.dot -o project_graph.svg
# PDF (for formal reports)
dot -Tpdf project.dot -o project_graph.pdf
Customizing Output
The generated .dot file may be verbose for large projects. You can filter targets using CMake variables:
cmake --graphviz=project.dot --graphviz-executables --graphviz-libraries .
Or manually edit the .dot file to focus on specific components:
# View just the relevant portion
grep -E "^[[:space:]]*(lib_a|lib_b|app_c)" project.dot
Advanced Usage
Inspecting the Raw DOT Format
Before converting to an image, examine the .dot file directly:
cat project.dot | head -20
You’ll see output like:
digraph "project_dependencies" {
node [shape=box];
"app_main" -> "lib_core";
"app_main" -> "lib_utils";
"lib_utils" -> "lib_core";
"lib_core" -> "zlib";
}
Each arrow represents a dependency: A -> B means A depends on B.
Identifying Bottleneck Libraries
Libraries with many incoming arrows are bottlenecks. They’re built early and block parallel compilation if they change frequently. Use grep to count:
grep -o '-> "lib_core"' project.dot | wc -l
If a library appears in dozens of dependencies, optimizing its build time yields significant gains.
Handling Circular Dependencies
Graphviz will render circular dependencies, making them immediately visible as cycles in the graph. If you see loops, your project has a real problem—CMake will catch this during configuration, but the visual is helpful for communicating the issue to team members.
Practical Workflow
For a monorepo or large project:
# Generate graph after any major CMakeLists.txt changes
cd build
cmake --graphviz=deps.dot ..
# Convert and open (macOS/Linux)
dot -Tsvg deps.dot -o deps.svg
open deps.svg # or xdg-open on Linux
# For automated CI/CD, commit the SVG
git add docs/dependencies.svg
Include the SVG in your project documentation. Update it when adding new targets or restructuring libraries.
Integration with Modern Tools
Many IDEs provide interactive dependency visualization:
- CLion: Built-in CMake dependency viewer (no extra setup needed)
- VS Code with CMake Tools: Right-click a target → “Show Dependency Graph”
- Visual Studio: Project dependency viewer (native, not Graphviz-based)
For CI/CD pipelines that don’t have GUI access, the command-line approach remains the standard. Generate graphs automatically on each build and store them as artifacts for review.
Performance Considerations
On very large projects (500+ targets), the generated .dot file may be enormous and slow to render. Split your project logically:
# Graph only a subdirectory's targets
cmake --graphviz=core_deps.dot . | grep -v "external\|third_party"
Or use a smaller scope by restructuring as separate CMake projects with well-defined interfaces.

Convert to svg file would be better. Which keeps the picture sharp. Especially for large projects.
dot -Tsvg dep.dot > dep.svg