<ulclass="tags-list"><li><ahref="/tags.html#tag-OCaml">OCaml</a></li><li><ahref="/tags.html#tag-MirageOS">MirageOS</a></li></ul><p>TL;DR: Passing runtime arguments around is tricky, and prone to change every other month.</p>
<p>We define the <ahref="https://erratique.ch/software/cmdliner/doc/Cmdliner/Term/index.html#type-t">Cmdliner.Term.t</a>
in line 6 (<code>let term = ..</code>) - which provides documentation ("How to say hello."), the option to
use (<code>["hello"]</code> - which is then translated to <code>--hello=</code>), that it is optional,
of type <code>string</code> (cmdliner allows you to convert the incoming strings to more
complex (or more narrow) data types, with decent error handling).</p>
<p>The defined argument is directly passed to <ahref="https://ocaml.org/p/mirage-runtime/4.8.1/doc/Mirage_runtime/index.html#val-register_arg"><code>Mirage_runtime.register_arg</code></a>,
(in line 7) so our binding <code>hello</code> is of type <code>unit -> string</code>.
In line 14, the value of the runtime argument is used (<code>hello ()</code>) for printing
a log message.</p>
<p>The nice property is that it is all local in <code>unikernel.ml</code>, there are no other
parts involved. It is just a bunch of API calls. The downside is that <code>hello ()</code>
should only be evaluated after the function <code>start</code> was called - since the
<code>Mirage_runtime</code> needs to parse and fill in the command line arguments. If you
call <code>hello ()</code> earlier, you'll get an exception "Called too early. Please delay
this call to after the start function of the unikernel.". Also, since
Mirage_runtime needs to collect and evaluate the command line arguments, the
<code>Mirage_runtime.register_arg</code> may only be called at top-level, otherwise you'll
get another exception "The function register_arg was called to late. Please call
register_arg before the start function is executed (e.g. in a top-level binding).".</p>
<p>Another advantage is, having it all in unikernel.ml means adding and removing
arguments doesn't need another execution of <code>mirage configure</code>. Also, any
type can be used that the unikernel depends on - the config.ml is compiled only
with a small set of dependencies (mirage itself) - and we don't want to impose a
large dependency cone for mirage just because someone may like to use
X509.Key_type.t as argument type.</p>
<p>Earlier, before mirage 4.5.0, we had runtime and configure arguments mixed
together. And code was generated when <code>mirage configure</code> was executed to
deal with these arguments. The downsides included: we needed serialization for
all command-line arguments (at configure time you could fill the argument, which
was then serialized, and deserialized at runtime and used unless the argument
was provided explicitly), they had to appear in <code>config.ml</code> (which also means
changing any would need an execution of <code>mirage configure</code>), since they generated code
potential errors were in code that the developer didn't write (though we had
some <code>__POS__</code> arguments to provide error locations in the developer code).</p>
<p>Related recent changes are:</p>
<ul>
<li>in mirage 4.8.1, the runtime arguments to configure the OCaml runtime system
(such as GC settings, randomization of hashtables, recording of backtraces)
are now provided using the <ahref="https://ocaml.org/p/cmdliner-stdlib">cmdliner-stdlib</a>
package.</li>
<li>in mirage 4.8.0, for git, dns-client, and happy-eyeballs devices the optional
arguments are generated by default - so they are always available and don't
need to be manually done by the unikernel developer.</li>
<p>In MirageOS, since the early stages (I'll go back to 2.7.0 (February 2016) where
functoria was introduced) used an embedded fork of <code>cmdliner</code> to handle command
line arguments.</p>
<p><ahref="https://asciinema.org/a/ruHoadi2oZGOzgzMKk5ZYoFgf"><imgsrc="https://asciinema.org/a/ruHoadi2oZGOzgzMKk5ZYoFgf.svg"alt="Animated changes to the hello world unikernel"></a></p>
<p>The history of hello world shows that over time we slowly improve the developer
experience, and removing the boilerplate needed to get MirageOS unikernels up
and running. This is work over a decade including lots of other (here invisible)
improvements to the mirage utility.</p>
<p>Our current goal is to minimize the code generated by mirage, since code
generation has lots of issues (e.g. error locations, naming, binary size). It
is a long journey. At the same time, we are working on improving the performance
of MirageOS unikernels, developing unikernels that are useful in the real
world (<ahref="https://github.com/robur-coop/miragevpn">VPN endpoint</a>, <ahref="https://github.com/robur-coop/dnsvizor">DNSmasq replacement</a>, ...), and also <ahref="https://github.com/robur-coop/mollymawk">simplifying the
deployment of MirageOS unikernels</a>.</p>
<p>If you're interested in MirageOS and using it in your domain, don't hesitate
to reach out to us (via eMail: team@robur.coop) - we're keen to deploy MirageOS
and find more domains where it is useful. If you can spare a dime, we're a
registered non-profit in Germany - and can provide tax-deductable receipts for