package b0

  1. Overview
  2. Docs

B0 driver development manual

A B0 driver like b0 or d0 is an executable that provides a service on the definitions of a B0 file. This manual shows how to develop a custom driver for B0 files.

Overview

The B0 file needs to be compiled and made accessible to the driver executable. At the moment the OCaml Dynlink API is not being used. Instead the driver executable relinks its objects with a compilation of the B0 file to produce an executable that is executed to run the driver on the definitions. With the help of the B0_driver API this all happens transparently in the .drivers directory of the _b0 directory.

The driver library

For your driver to access a B0 file you need to create an OCaml library which has all the objects of your driver and registers your main function by calling B0_driver.set.

Source wise a typical driver source structure is:

src/mydriver_main.ml
src/mydriver_main_run.ml

The mydriver_main.ml file implements and registers the driver. It's compiled object should be part of your driver library. Here's a minimal example:

open B0_std
open Cmdliner

let driver =
  let name = "mydriver" and version = "v0.0.1" in
  let libs = ["mydriver"] in
  B0_driver.create ~name ~version ~libs

let my_driver conf =
  Fmt.pr "Running!@.";
  B0_driver.Exit.ok

let my_driver =
  let doc = "My driver" in
  let sdocs = Manpage.s_common_options in
  let exits = B0_driver.Exit.Info.base_cmd in
  let man = [ `S Manpage.s_description; "$(mname) does bla" ] in
  B0_driver.cmd_with_b0_file ~driver (Term.const unit_cmd),
  Term.info "mydriver" ~version:"v0.0.1" ~doc ~sdocs ~exits ~man

let main () = Term.eval mydrivery
let () = B0_driver.set driver ~main

The mydriver_main_run.ml file defines your driver executable when it has no B0 file linked in. It's the program that runs your driver without the B0 file linked in. It should simply be:

let () =
  let module D = Mydriver_main (* make sure we link it *) in
  if !Sys.interactive then () else B0_driver.run ~has_b0_file:false

A few things to note:

  • Your driver library must be installed and available in the OCAMLPATH under the name you gave in to B0_driver.
  • The driver library's directory is not added to the includes for compiling the B0 file. This prevents drivers from adding declarations to the compilation environment since using them in a B0 file would then break other drivers. New declarations must always be explicitely imported in the B0 file by using the #require directive.

FIXME

The driver dance seems to be a bit slow for now. Even for the up-to-date dance we get into the 165 ms b0 unit list. But there's room for improvement. Here are different things to consider that could be done.

  • Cold driver compilation. I think we get hit a bit by the executable link phase (globally 500ms, but the compilation spawn takes 480ms). Investigate what makes OCaml linking faster, e.g. removes the -linkall but then we need to mention the module of the driver library that calls B0_driver.set in the expanded B0 file (doable, see if it's worth the ms). Alternatively consider using Dylink once it gets lib support, but then what about platforms that don't support it.
  • The various timing obtained with b0 file log --stats and b0 -v -v don't add up to what time b0 reports. Investigate, is it the execv ?
  • Try to jump directly into the compiled driver executable and let it auto verify and auto recompile if needed ? This could allow to share part of the hash cache in the future.
  • Maybe go back to use an ad-hoc stamp for driver compilation rather than use B00 itself.