Skip to content

Instantly share code, notes, and snippets.

@samoht
Last active April 5, 2024 08:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samoht/98127448fcf6a2483fa36099649fba5a to your computer and use it in GitHub Desktop.
Save samoht/98127448fcf6a2483fa36099649fba5a to your computer and use it in GitHub Desktop.

Mirage Compilation Process

This document details the details of the compilation process for MirageOS unikernels. It outlines the steps required to prepare, compile, and manage dependencies for Mirage applications.

Overview of the Compilation Process

Developing a simple application with Mirage involves starting with two primary files:

  • config.ml: Contains the configuration of your unikernel.
  • unikernel.ml: The main application code.

The usual workflow to configure and compile an unikernel is to run the following commands:

$ mirage configure <configure-options>
$ make depends
$ dune build
$ ls dist/
<unikernel binaries>

While hidden to the end-user, mirage configure is actually split into several lower-level key steps, described below.

Configuration

Step 1: Initial Configuration

Executing mirage configure --init-config generates the essential scaffolding needed for compiling and executing config.exe. This process creates the following files, if they don't already exist:

Makefile
dune-project
dune-workspace
dune.config
dune

These files are generic and independent of the specific content within config.ml. Their primary role is to enable the compilation of config.exe, which provides a runnable description of the unikernel. For example:

$ ./config.exe query name
<unikernel-name>

For additional options and details, see the output of ./config.exe --help. The config.exe binary drives the remaining setup process.

Step 2: Persisting CLI options

The mirage command-line tool supports multiple sub-commands, designed to be used in a specific sequence. For example:

Copy code
$ mirage configure <options>
...
$ mirage describe
...
$ mirage clean

In this workflow, users expect that mirage describe will detail the unikernel as configured, not in its generic form. Similarly, mirage clean should remove all files generated during the configuration step. This implies that the CLI maintains state across invocations by remembering the options passed to mirage configure. To do this, mirage configure <options> records the specified options in a .mirage file.

Note: The .mirage file is exclusively created by the mirage configure command. While config.exe may read from this file, it will not modify or create it.

Step 3: Library Initialization

The command mirage configure --init-lib lays down the scaffolding necessary for compiling the unikernel functor as a library. This action is also achievable by running ./config.exe configure --init-lib.

This step modifies the existing dune file with specific rules to compile the provided functor as a library. The output is an OCaml library with the same name as the unikernel defined in config.ml.

Step 4: Application Configuration

Running mirage configure --init-app ... with the desired CLI options configures the final application. This can also be done through ./config.exe configure --init-app ....

This generates a new mirage directory, containing all files required to compile and package the application:

mirage/main.ml
mirage/app.opam
mirage/dune
mirage/...

Notes: Generated Files and Overwrite Rules

If a generated file already exists, its potential overwriting follows these rules:

  • Files starting with ;; generated by mirage <version> will be overwritten.
  • Files without this header will not be modified.

The mirage clean command also uses these rules to determine which files to delete or retain. Files marked as generated are removed, while others are left untouched. If you wish to edit and preserve any generated file, ensure to remove the "generated by" header.

Notes: Using PPX or Libraries in config.ml

To use PPX extensions or libraries within config.ml, first edit dune.config by removing the "generated by" header. Then, customize the compilation rules as needed.

Dependency Management

Note: This section may evolve with future dune pkg updates.

Managing Lock Files

Generated dune files include an alias for creating lock files, which are crucial for packaging: execute dune build @lock (or make lock)

During development, it could be beneficial to have a single lock file for all the unikernels in the repository. Use make dev-lock to create one such file.

Pulling Dependencies

An alias in the generated dune files allows for pulling dependencies into a local duniverse folder: run dune build @pull (or make pull).

During development, it could be useful to pull all dependencies of all the unikernels. Use dune build @dev-pull or make dev-pull to achieve this.

Pulling External Dependencies

TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment