package ppx_module
Install
dune-project
Dependency
Authors
Maintainers
Sources
sha256=5cac9f2a43bf47bb6829ebbf31ba945117f95947c1334252052dac55fd29dc3e
sha512=73710780e913b33b07e835943de5669e43ccbdaa2de6ad869e64d5dcfb9264f8be37b8cd2ed2ce6311acce5a49484cc951cd652a8983ccf23a75e60c986fa03f
Description
An OCaml PPX and runtime library for recording module instantiation graphs. Annotated modules record functor argument dependencies and captured outer contexts. The resulting graphs can be printed as Graphviz DOT.
Added to opam-repository:
README
ppx_module
ppx_module is an OCaml PPX and small runtime library for recording module instantiation graphs.
It is meant for codebases that use module functors heavily and need a way to inspect which instantiated module depends on which functor argument or captured outer context. The generated graph can be printed as Graphviz DOT.
What It Does
Annotate a module binding with [@@ppx_module]:
module Domain = struct
let value = 1
end
[@@ppx_module]The PPX appends two values to the module body:
val ppx_module_name : string Lazy.t
val ppx_module_node : Ppx_module.node Lazy.tAt runtime, forcing ppx_module_node registers a node in the module graph. Ppx_module.pp can then print the graph rooted at that node.
Attributes
The attribute can be bare:
[@@ppx_module]or can take a record payload:
[@@ppx_module { name = "Memory.Domain"; cluster = "memory"; parents = true }]Supported fields:
name: display name for the graph node. If omitted, the capitalized source filename is used.cluster: optional Graphviz cluster name. Some names have predefined colors:memory,scalar,address,offset,value,wrapper, andchecks.parents: whether functor parameters should be recorded as parent dependencies. Defaults totrue.
Functor Dependencies
For an annotated functor, named functor parameters are recorded as Parent edges:
module Make (Input : Ppx_module.LOGGED) : sig
include Ppx_module.LOGGED
end = struct
end
[@@ppx_module { name = "Make" }]The generated node for Make(Input) will point to Input.ppx_module_node.
Nested annotated modules inside an annotated functor also record outer functor parameters as Context edges:
module Outer (Ctx : Ppx_module.LOGGED) = struct
module Inner = struct
end
[@@ppx_module { name = "Inner" }]
end
[@@ppx_module { name = "Outer" }]Here, Inner records that it captured Ctx from its enclosing context.
Printing A Graph
Force a generated node, then pass it to Ppx_module.pp:
let () =
let root = Lazy.force My_module.ppx_module_node in
Format.printf "%a@." Ppx_module.pp rootThe output is Graphviz DOT:
digraph module_stack {
...
}To render it:
dune exec ./my_program.exe > graph.dot
dot -Tsvg graph.dot > graph.svgUse reachable-only mode when you do not want unrelated registered nodes:
Format.printf "%a@." (Ppx_module.pp ~mode:Ppx_module.Reachable) rootDisable source line numbers in node labels when you only want filenames:
Format.printf "%a@." (Ppx_module.pp ~line_numbers:false) rootModule Signatures
If an annotated module has an explicit signature and callers need access to the generated values, include Ppx_module.LOGGED:
module M : sig
include Ppx_module.LOGGED
val value : int
end = struct
let value = 1
end
[@@ppx_module { name = "M" }]Dune Setup
Depend on the runtime library and enable the PPX:
(executable
(name main)
(libraries ppx_module)
(preprocess
(pps ppx_module.ppx)))For libraries:
(library
(name my_lib)
(libraries ppx_module)
(preprocess
(pps ppx_module.ppx)))Development
Build and run the tests with:
dune runtestThe tests cover recursive modules, default and explicit names, clusters, functor parameter edges, disabled parent edges, context edges, and DOT output fragments.