Legend:
Library
Module
Module type
Parameter
Class
Class type
The jenga monad. It has two pieces to it:
an implicit accumulator of dependencies, that Dep.path and all the functions that return a unit t add to. The final value of this accumulator is the dependencies of the action in Rule.create and Dep.action, and what gets built in the case of Rule.alias
a monad and other usual combinators, which allows to write computation that ask jenga to build something and wait for the result (and to rebuild if that input changes). Because of this, functions should not be side-effecting.
To make clear the distinction between the two, take:
val path : Path.t -> unit t val contents : Path.t -> string t
path simply says that the surrounding Rule.create (for instance) will read the contents of that file. contents allows to create different action depending on the contents of the file.
It's highly recommended to use parallel combinators like both and all in preference to bind. Using bind is inherently sequential, whereas usually work in a build system can be done in parallel.
let v = memoize ~name t behaves like t, except with caching: using v in several computations will not result in duplicate evaluations of t. name is used in displayed in errors, or in the case of dependency cycles.
group_dependencies t is equivalent to t, however jenga will be careful to avoid duplicating the set of dependencies that have been declared. This is best used under an alias, as the alias will allow to share the computation as well.
source_if_it_exists Dont treat path as a goal (i.e. don't force it to be built) Just depend on its contents, if it exists. It's ok if it doesn't exist.
The semantics of glob_listing and glob_change includes files which exist on the file-system AND files which are buildable by some jenga rule. Therefore it is an error (dependency cycle) to glob a directory while generating the scheme for that same directory. Use Scheme.glob instead.