Module B00.Memo

Build memoizer.

A memoizer ties together and environment, an operation cache, a guard and an executor.


type feedback = [
| `Miss_tool of Tool.t * string
| `Op_cache_error of B000.Op.t * string
| `Op_complete of B000.Op.t

The type for memoizer feedback.

type t

The type for memoizers. This ties together an environment, a guard, an operation cache and an executor.

val create : ?⁠clock:B0_std.Time.counter -> ?⁠cpu_clock:B0_std.Time.cpu_counter -> feedback:(feedback -> unit) -> cwd:B0_std.Fpath.t -> Env.t -> B000.Guard.t -> B000.Reviver.t -> B000.Exec.t -> t
val memo : ?⁠hash_fun:(module B0_std.Hash.T) -> ?⁠env:B0_std.Os.Env.t -> ?⁠cwd:B0_std.Fpath.t -> ?⁠cache_dir:B0_std.Fpath.t -> ?⁠trash_dir:B0_std.Fpath.t -> ?⁠jobs:int -> ?⁠feedback:([ feedback | | ] -> unit) -> unit -> (t, string) Stdlib.result

memo is a simpler create

  • hash_fun defaults to B000.Op_cache.create's default.
  • jobs defaults to B00.Exec.create's default.
  • env defaults to B0_std.Os.Env.current
  • cwd defaults to Current working directory (cwd)
  • cache_dir defaults to Fpath.(cwd / "_b0" / ".cache")
  • trash_dir defaults to Fpath.(cwd / "_b0" / ".trash")
  • feedback defaults formats feedback on stdout.
val clock : t -> B0_std.Time.counter

clock m is m's clock.

val cpu_clock : t -> B0_std.Time.cpu_counter

cpu_clock m is m's cpu clock.

val env : t -> Env.t

env m is m's environment.

val reviver : t -> B000.Reviver.t

reviver m is m's reviver.

val guard : t -> B000.Guard.t

guard m is m's guard.

val exec : t -> B000.Exec.t

exec m is m's executors.

val trash : t -> B000.Trash.t

trash m is m's trash.

val has_failures : t -> bool

has_failures m is true iff at least one operation (or fiber) has failed.

val hash_string : t -> string -> B0_std.Hash.t

hash_string m s is B000.Reviver.hash_string (reviver m) s.

val hash_file : t -> B0_std.Fpath.t -> (B0_std.Hash.t, string) Stdlib.result

hash_file m f is B000.Reviver.hash_file (reviver m) f. Note that these file hashes operations are memoized.

val stir : block:bool -> t -> unit

stir ~block m runs the memoizer a bit. If block is true blocks until the memoizer is stuck with no operation and fibers to execute.

type error =
| Failures

Some operations failed.

| Cycle of B000.Op.t list

Cyclic dependency.

| Never_became_ready of B0_std.Fpath.Set.t

Some files never became ready.

The type for memo finish errors.

val status : t -> (unit, error) Stdlib.result

status m looks ops m and returns:

  • Ok (), if all operations in m B000.Op.Executed.
  • Error Failures, if there exists an operation that B000.Op.status.Failed (and hence also if a fiber failed, see here).
  • Error (Cycle ops), if there is a set of B000.Op.status.Waiting operations whose individual reads and writes leads to a dependency cycle.
  • Error (Never_became_ready fs), with fs files that are in the reads of B000.Op.status.Waiting operations but are written by no known operation.

Usually called after a blocking stir to check everything executed as expected. The function itself has no effect more and can be added on m afterwards. If you are only interested in checking if a failure occured in the memo has_failures is faster.

val delete_trash : block:bool -> t -> (unit, string) Stdlib.result

delete_trash ~block m is B000.Trash.delete ~block (trash m).

val ops : t -> B000.Op.t list

ops m is the list of operations that were submitted to the memoizer

Futures and fibers

type 'a fiber = ('a -> unit) -> unit

The type for memoizer fibers returning values of type 'a. A fiber f k represent a thread of execution that eventually kontinues k with its result value when it reaches an end.

Fibers should always be run on a Memo via spawn_fiber or as the continuation of a build operation. A fiber can fail either explictly via fail or because an uncaught exception occurs. In both these cases a `Fail notify operation gets added to the memo to witness the fiber failure. The status of this operation is like any Fail notify: B000.Op.status.Failed.

val spawn_fiber : t -> unit fiber

run m k calls k () asynchronously and handles any fiber failure. This also catches non-asynchronous uncaught exceptions and turns them into `Fail notification operations.

val fail : t -> ('a, Stdlib.Format.formatter, unit, 'b) Stdlib.format4 -> 'a

fail m fmt ... fails the fiber via a notify operation.

val fail_if_error : t -> ('a, string) Stdlib.result -> 'a

fail_if_error m r is v if r is Ok v and fail m "%s" e if r is Error _.

module Fut : sig ... end

Future values.

Operation groups

val group : t -> string

group m is m's group.

val with_group : t -> string -> t

group m g is m but operations performed on m have group g.


val notify : ?⁠k:(unit -> unit) -> t -> [ `Fail | `Warn | `Start | `End | `Info ] -> ('a, Stdlib.Format.formatter, unit, unit) Stdlib.format4 -> 'a

notify m kind msg is a notification msg of kind kind. Note that a `Fail notification will entail a finish_error, see also fail and fail_if_error.

Files and directories

val file_ready : t -> B0_std.Fpath.t -> unit

ready m p declares path p to be ready, that is exists and is up-to-date in b. This is typically used with source files and files external to the build (e.g. installed libraries).

val read : t -> B0_std.Fpath.t -> string fiber

read m file k reads the contents of file file as s when it becomes ready and continues with k s.

val write : t -> ?⁠stamp:string -> ?⁠reads:B0_std.Fpath.t list -> ?⁠mode:int -> B0_std.Fpath.t -> (unit -> (string, string) Stdlib.result) -> unit

write m ~reads file w writes file with data w () and mode mode (defaults to 0o644) when reads are ready. w's result must only depend on reads and stamp (defaults to "").

val copy : t -> ?⁠mode:int -> ?⁠linenum:int -> src:B0_std.Fpath.t -> B0_std.Fpath.t -> unit

copy m ~mode ?linenum ~src dst copies file src to dst with mode mode (defaults to 0o644) when src is ready. If linenum is specified, the following line number directive is prependend in dst to the contents of src:

#line $(linenum) "$(src)"
val mkdir : t -> ?⁠mode:int -> B0_std.Fpath.t -> unit fiber

mkdir m dir p creates the directory path p with mode mode (defaults to 0o755) and continues with k () whne dir is available. The behaviour with respect to file permission matches Os.Dir.create.

val delete : t -> B0_std.Fpath.t -> unit fiber

delete m p deletes (trashes in fact) path p and continues with k () when the path p is free to use.

val wait_files : t -> B0_std.Fpath.t list -> unit fiber

wait_files m files k continues with k () when files become ready. FIXME Unclear whether we really want this.

Memoizing tool spawns

type tool

The type for memoized tools.

type cmd

The type for memoized tool invocations.

val tool : t -> Tool.t -> B0_std.Cmd.t -> cmd

tool m t is tool t memoized. Use the resulting function to spawn the tool with the given arguments.

val tool_opt : t -> Tool.t -> (B0_std.Cmd.t -> cmd) option

tool_opt m t is like tool, except None is returned if the tool cannot be found.

val spawn : t -> ?⁠stamp:string -> ?⁠reads:B0_std.Fpath.t list -> ?⁠writes:B0_std.Fpath.t list -> ?⁠env:B0_std.Os.Env.t -> ?⁠cwd:B0_std.Fpath.t -> ?⁠stdin:B0_std.Fpath.t -> ?⁠stdout:B000.Op.Spawn.stdo -> ?⁠stderr:B000.Op.Spawn.stdo -> ?⁠success_exits:B000.Op.Spawn.success_exits -> ?⁠post_exec:(B000.Op.t -> unit) -> ?⁠k:(int -> unit) -> cmd -> unit

spawn m ~reads ~writes ~env ~cwd ~stdin ~stdout ~stderr ~success_exits cmd spawns cmd once reads files are ready and makes files writes ready if the spawn succeeds and the file exists. The rest of the arguments are:

  • stdin reads input from the given file. If unspecified reads from the standard input of the program running the build. Warning. The file is not automatically added to reads, this allows for example to use B0_std.Os.File.null.
  • stdout and stderr, the redirections for the standard outputs of the command, see stdo. Path to files are created if needed. Warning. File redirections are not automatically added to writes; this allows for example to use B0_std.Os.File.null.
  • success_exits the exit codes that determine if the build operation is successful (defaults to 0, use [] to always succeed)
  • env, environment variables added to the build environment. This overrides environment variables read by the tool in the build environment except for forced one. It also allows to specify environment that may not be mentioned by the running tool's environment specification.
  • cwd the current working directory. Default is cwd. In general it's better to avoid using relative file paths and tweaking the cwd. Construct your paths using the absolute directory functions and make your invocations independent from the cwd.
  • post_exec, if specified is called with the build operation after it has been executed or revived. If it was executed this is called before the operation gets recorded. It can be used to define the reads and writes of the operation if they are difficult to find out before hand. Do not access m in that function.
  • k, if specified a fiber invoked once the spawn has succesfully executed with the exit code.
  • stamp is used for caching if two spawns diff only in their stamp they will cache to different keys. This can be used to memoize tool whose outputs may not entirely depend on the environment, the cli stamp and the the content of read files.

Note. If the tool spawn acts on a sort of "main" file (e.g. a source file) it should be specified as the first element of reads, this is interpreted specially by certain build tracer.