Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gidd

gidd turns GCC/G++ -H include traces or captured compiler invocations into dependency diagrams for C and C++ projects. It parses include nesting, keeps graph nodes keyed by normalized paths, applies optional path-prefix filters, and writes Graphviz DOT, PlantUML, JSON, and a self-contained interactive HTML viewer.

Usage

Build And Test

cmake -S . -B build
cmake --build build
ctest --test-dir build

The default build always produces gidd and gidd-capture. If CMake can find LLVM and Clang development packages, gidd-capture is built with the Clang-backed scanner; otherwise it still passes compiler invocations through but records scan failures.

Generate Diagrams From A Trace

The current command reads input.txt and optional filter.txt from the working directory, then writes clustered and unclustered diagrams plus JSON and HTML viewer reports with the output prefix:

./gidd

./gidd --capture-dir <dir> is the only supported command-line option. Other input paths, output prefixes, selected formats, and cluster modes are currently fixed in the entry point.

Generated files:

output.dot
output_no_clusters.dot
output.puml
output_no_clusters.puml
output.json
output.html

To capture an include trace from a CMake project, add -H to the compiler flags used by the target you want to inspect, then capture a single-threaded rebuild:

cmake --build build --clean-first -- -j1 > input.txt 2>&1
./gidd

Experimental Compiler Invocation Capture

When built with LLVM/Clang development libraries, gidd-capture can be used as a transparent compiler wrapper. It runs the real compiler first, then records nested include dependencies for successful compile commands under GIDD_TRACE_DIR.

For CMake, prefer compiler launcher mode:

cmake -S . -B build \
  -DCMAKE_C_COMPILER_LAUNCHER=/path/to/gidd-capture \
  -DCMAKE_CXX_COMPILER_LAUNCHER=/path/to/gidd-capture
GIDD_TRACE_DIR=$PWD/build/gidd-trace cmake --build build
./gidd --capture-dir build/gidd-trace

gidd-capture can also be used as CC or CXX when the real compiler is provided explicitly:

GIDD_REAL_CXX=clang++ \
CXX=/path/to/gidd-capture \
cmake -S . -B build
GIDD_TRACE_DIR=$PWD/build/gidd-trace \
GIDD_REAL_CXX=clang++ \
cmake --build build

If the real compiler succeeds but Clang cannot replay the command for scanning, the build still succeeds and the capture record contains the scan diagnostic.

Filter Dependencies

Create filter.txt next to input.txt with one normalized path prefix per line:

/usr/include
/opt/vendor

Any dependency is omitted when either endpoint starts with a filter prefix.

Parser Example

This example is simplified from the tests:

std::stringstream input;
input << "[ 50%] Building CXX object CMakeFiles/app.dir/src/app.cpp.o\n";
input << ". /project/include/app.h\n";
input << ".. /project/include/detail/config.h\n";

gidd::IncludeGraph graph = gidd::parseGccIncludeTrace(input);

assert(graph.roots.count("src/app.cpp") == 1);
assert(graph.dependencies.count({"src/app.cpp", "/project/include/app.h"}) == 1);
assert(graph.dependencies.count({"/project/include/app.h",
                                  "/project/include/detail/config.h"}) == 1);

API Reference

gidd::IncludeGraph

struct IncludeGraph { std::set<std::pair<std::string, std::string>> dependencies; std::set<std::string> roots; };

In-memory dependency graph. dependencies stores directed edges between normalized path node ids; roots stores translation-unit roots parsed from compiler object lines.

gidd::parseGccIncludeTrace

IncludeGraph parseGccIncludeTrace(std::istream &input);

Parses GCC/G++ -H include trace lines and CMake Building CXX object / Building C object translation-unit markers into an IncludeGraph.

Path And Graph Helpers

std::string normalizePath(std::string path);

Lexically normalizes a path without touching the filesystem. It converts separators to /, collapses repeated separators and ., and resolves safe .. segments.

std::set<std::string> graphNodes(const IncludeGraph &graph);

Returns every node mentioned by graph roots or dependency endpoints.

std::map<std::string, std::set<std::string>> nodesByDirectory(const IncludeGraph &graph);

Groups graph nodes by the directory portion of their normalized node id.

std::map<std::string, std::string> displayLabels(const IncludeGraph &graph);

Returns readable labels for diagram nodes. Unique basenames use the basename; duplicate basenames include the minimal parent path needed to disambiguate.

bool dependencyMatchesFilter(const std::pair<std::string, std::string> &dependency, const std::vector<std::string> &filters);

Returns true when either dependency endpoint starts with a normalized filter prefix.

Interactive Viewer

output.html embeds the filtered include graph and opens directly in a browser. It starts from translation-unit roots, lets you search files by path, expand direct or reverse include relationships, fold selected subgraphs, pan/zoom the graph, hide multiple path prefixes such as /usr/include or a specific header, highlight full upstream/downstream paths for a selected file, collapse either side panel to focus on the graph, and inspect incoming/outgoing includes. Browser-side path filters hide directly matched files and folders, then keep shared downstream headers visible when they are still reachable from an unfiltered source.

output.json contains the same filtered graph data for other tools:

{
  "nodes": [{"id": "src/app.cpp", "label": "app.cpp", "directory": "src", "kind": "root", "root": true}],
  "edges": [{"from": "src/app.cpp", "to": "/project/include/app.h"}],
  "roots": ["src/app.cpp"]
}

Capture Records

When GIDD_TRACE_DIR is set, gidd-capture writes one JSON record per successful real compiler invocation. Record filenames are derived from the working directory, compiler arguments, and process id, and are not intended as a stable public API.

{
  "working_directory": "/tmp/build",
  "arguments": ["-Iinclude", "src/app.cpp"],
  "translation_unit": "src/app.cpp",
  "scan_succeeded": true,
  "diagnostics": [],
  "dependencies": [
    {"from": "src/app.cpp", "to": "/project/include/app.h"}
  ]
}

./gidd --capture-dir <dir> reads .json files in that directory, skips malformed records with a stderr diagnostic, skips records where scan_succeeded is false, and merges the remaining dependencies into the same writer pipeline used for trace input.

Current Limitations And Failure Behavior

  • Missing input.txt is treated as an empty trace and still writes empty outputs.
  • Missing filter.txt means no filters are applied.
  • Trace parsing is permissive: unknown non-trace lines are ignored.
  • gidd-capture returns the real compiler's non-zero exit status and does not write a capture record for failed compiles.
  • If the real compiler succeeds but include scanning fails, the wrapper still returns success and writes a record with diagnostics when GIDD_TRACE_DIR is set.
  • gidd returns non-zero when any requested output file cannot be written.

Output Formats

const std::vector<OutputFormatInfo> &supportedOutputFormats();

Returns the registered diagram/report formats. The current formats are dot, puml, json, and html.

bool parseOutputFormat(const std::string &name, OutputFormat *format);

Maps a format registry name to an OutputFormat.

std::vector<OutputFormat> defaultOutputFormats();

Returns the formats emitted by the current CLI entry point: DOT, PlantUML, JSON, and HTML.

Diagram Writing

bool writeDiagram(OutputFormat format, const std::string &output_prefix, const std::vector<std::string> &filters, const IncludeGraph &graph, const DiagramOptions &options);

Writes one DOT, PlantUML, JSON, or HTML diagram/report using the requested output prefix, path-prefix filters, graph, and clustering option where applicable.

Examples

Here is an example of how a tiny hello world include graph can look:

#include <cstdio>

int main() {
    printf("Hello, World!\n");
}

output_no_clusters.dot: Hello world dot no clusters

output.dot: Hello world dot

output_no_clusters.puml: Hello world plantuml no clusters

output.puml: Hello world plantuml

About

Generate include dependency diagram

Resources

Stars

12 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages