Memoizer
The type for memoizer feedback. FIXME remove `Miss_tool now that we have notify operations.
The type for memoizers. This ties together an environment, a guard, an operation cache and an executor.
val create : ?clock:B00_std.Time.counter -> ?cpu_clock:B00_std.Time.cpu_counter -> feedback:(feedback -> unit) -> cwd:B00_std.Fpath.t -> Env.t -> B000.Guard.t -> B000.Reviver.t -> B000.Exec.t -> t
val memo : ?hash_fun:(module B00_std.Hash.T) -> ?env:B00_std.Os.Env.t -> ?cwd:B00_std.Fpath.t -> ?cache_dir:B00_std.Fpath.t -> ?trash_dir:B00_std.Fpath.t -> ?jobs:int -> ?feedback:([ feedback | B000.Exec.feedback ] -> unit) -> unit -> (t, string) Stdlib.result
memo
is a simpler create
hash_fun
defaults toB00_std.Hash.Xxh_64
.jobs
defaults toB00_std.Os.Cpu.logical_count
.env
defaults toB00_std.Os.Env.current
cwd
defaults toB00_std.Os.Dir:cwd
cache_dir
defaults toFpath.(cwd / "_b0" / ".cache")
trash_dir
defaults toFpath.(cwd / "_b0" / ".trash")
feedback
defaults to a nop.
val clock : t -> B00_std.Time.counter
clock m
is m
's clock.
val cpu_clock : t -> B00_std.Time.cpu_counter
cpu_clock m
is m
's cpu clock.
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 -> B00_std.Hash.t
hash_string m s
is B000.Reviver.hash_string
(reviver m) s
.
val hash_file : t -> B00_std.Fpath.t -> (B00_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.
val status : t -> (unit, B000.Op.aggregate_error) Stdlib.result
status m
looks for aggregate errors in m
in ops m
, see B000.Op.aggregate_error
for details.
Usually called after a blocking stir
to check everything executed as expected. The function itself has no effect more operations can be 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)
.
Activity marks
val mark : t -> string
mark m
is m
's mark.
Futures and fibers
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
.
run m k
calls k ()
asynchronously and handles any fiber fail
ure. 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.
Feedback
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
.
val notify_if_error : t -> [ `Fail | `Warn | `Start | `End | `Info ] -> use:'a -> ('a, string) Stdlib.result -> 'a
notify_if_error m kind ~use r
is v
if r
is Ok v
. If r
is Error e
, a notification of kind kind
is added to m
and use
is returned. Note that a `Fail
notification will entail a finish_error
, see also fail
and fail_if_error
.
Files and directories
val file_ready : t -> B00_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 -> B00_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:B00_std.Fpath.t list -> ?mode:int -> B00_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:B00_std.Fpath.t -> B00_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 -> B00_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 -> B00_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 -> B00_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
val tool : t -> Tool.t -> B00_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 -> (B00_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:B00_std.Fpath.t list -> ?writes:B00_std.Fpath.t list -> ?env:B00_std.Os.Env.t -> ?cwd:B00_std.Fpath.t -> ?stdin:B00_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 toreads
, this allows for example to useB00_std.Os.File.null
.stdout
andstderr
, the redirections for the standard outputs of the command, seestdo
. Path to files are created if needed. Warning. File redirections are not automatically added towrites
; this allows for example to useB00_std.Os.File.null
.success_exits
the exit codes that determine if the build operation is successful (defaults to0
, 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 iscwd
. In general it's better to avoid using relative file paths and tweaking thecwd
. Construct your paths using the absolute directory functions and make your invocations independent from thecwd
.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 thereads
andwrites
of the operation if they are difficult to find out before hand. Do not accessm
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.
val spawn' : t -> ?stamp:string -> ?reads:B00_std.Fpath.t list -> writes_root:B00_std.Fpath.t -> ?writes:(B000.Op.t -> B00_std.Fpath.t list) -> ?env:B00_std.Os.Env.t -> ?cwd:B00_std.Fpath.t -> ?stdin:B00_std.Fpath.t -> ?stdout:B000.Op.Spawn.stdo -> ?stderr:B000.Op.Spawn.stdo -> ?success_exits:B000.Op.Spawn.success_exits -> ?k:(int -> unit) -> cmd -> unit
spawn'
is like spawn
except the actual file paths written by the spawn need not be determined before the spawn. Only the root directory of writes need to be specified via writes_root
. After the spawn executes the writes can be determined via the writes
function, the returned paths must be absolute and be prefixed by writes_root
(defaults to recursively list all the files rootet in writes_root
).