This repository provides useful Nix flakes/packages for developing and building systems based on the Genode OS Framework. Some familiarity with Nix (flakes) is recommended.
The following sections assume a working Nix installation with flakes enabled. See the official documentation for instructions for enabling Nix flakes.
This flake provides a containing a simple directory structure for a single Genode package.
To clone the provided flake template and create a new Genode package, run the following command.
nix flake new -t github:zgzollers/nixpkgs-genode#genode ./genode-project
Nix flakes can only access files that are added to a git repository. To initialize a new repository in the flake directory, run
git init && git add .
Make any desired changes to the initial template, then create the initial flake lock file by running
nix flake update && git add flake.lock
Finally, commit the changes. For some yet-unclear reason, the Genode build system will fail to build/run system scenarios and components if the initial flake template (in particular the .gitignore
) is not committed to the repository.
git commit -m "Initial commit"
Note that in order for Nix flakes to access a source file, it must be tracked by (not necessarily committed to) the repository containing the flake. See the official documentation for more information.
The template contains a sample Genode repository with a single "hello" application and runscript from the Genode Foundations book. This demo provides a nice opportunity to demonstrate the various ways this flake can be used, and ensure Nix is set up correctly.
To produce the system image for the demo scenario, we may build the package provided by the flake using the following command.
nix build
This will produce an ISO image located at result
(which is a symbolic link to the produced image stored in the Nix store). You can run this image on Genode supported hardware, or in QEMU.
qemu-system-x86_64 -cdrom result -m 64 -nographic
It is often preferable to tinker with source code in a more interactive environment. Nix provides a tool for creating reproducible shell environments. To prepare all dependencies and required sources, simply enter the Nix shell using the following command.
nix develop
If you prefer not to use nix flakes, nix-shell
may be used in place of the above command. Both of these commands will set a few useful environment variables.
Variable | Default Value | Description |
---|---|---|
SOURCE_DIR |
"$(pwd)/.build" |
Working directory for the build steps |
GENODE_DIR |
"${SOURCE_DIR}/genode" |
Location of the root of the working copy of the Genode source tree |
CONTRIB_DIR |
"${GENODE_DIR}/contrib" |
Location of prepared ports |
BUILD_DIR |
"${SOURCE_DIR}/build" |
Location of the Genode build directory |
These paths will not be created until you run the unpackPhase
using the following command.
runPhase unpackPhase
This will create a .build
subdirectory in the current working directory, populate it with the source codes and binary files required to build the derivation, and change to the $BUILD_DIR
directory. Note that this directory persists after exiting the Nix shell. Subsequent executions of the unpackPhase
will overwrite the contents of the .build
directory. To preserve intermediate compilations when developing, avoid rerunning the unpackPhase
upon returning to the Nix shell environment.
You can execute Genode tools/helper scripts located at $GENODE_DIR/tool
. For example, additional ports can be prepared by running the following command.
${GENODE_DIR}/tool/ports/prepare_port . . .
The demo scenario can be built by running the buildPhase
.
runPhase buildPhase
To facilitate packaging of Genode build artifacts with Nix, this flake provides a genodeEnv
package. Similar to the Nix stdenv
package, it contains a set of common packages necessary to build most Genode scenarios. Additionally, it provides a patched Genode source tree, and functions for building derivations and preparing additional dependencies (e.g., ports). Interaction with this environment is done primarily through the mkDerivation
function provided by genodeEnv
(not to be confused with mkDerivation
provided by stdenv
).
In the following sections, we will describe basic usage of this function to support common use cases. For more in-depth documentation of genodeEnv
, please refer to the reference provided in this repository.
In all but the simplest of cases, additional dependencies will be required to build a Genode package. The genodeEnv
only provides a few packages (in addition to those provided by stdenv
) required to run Makefiles and scripts in the $GENODE_DIR/tool
directory. To specify additional dependencies (including ports, libraries, and tools), add the corresponding Nix package to the buildInputs
argument of gendeEnv.mkDerivation
. For example, when placed in the flake.nix
file (as is the case in the template), the genodeEnv.mkDerivation
call may look like the following.
. . .
genodeEnv.mkDerivation {
name = "my-package";
buildInputs = with genode-utils.packages.${system}; [
grub2
nova
];
}
. . .
This will add the nova
and grub2
ports to the contrib
directory at build time.
By default, all repositories included in the Genode source tree are made available at build time (i.e., added to the REPOSITORIES
variable in build.conf
). To provide additional repositories, add them to the repos
argument. For example, in the flake template, a Genode repository is provided in the same directory as the flake.nix
file. This repository may be included at build time by adding the following to the genode.mkDerivation
call.
. . .
genodeEnv.mkDerivation {
name = "my-package";
buildInputs = with genode-utils.packages.${system}; [
grub2
nova
];
repos = [
./.
];
}
. . .
This both makes the source accessible at build time and adds it to the REPOSITORIES
variable in the generated build.conf
.
With all dependencies supplied and sources prepared, we may now supply the commands to build and install the desired artifacts. The genodeEnv.mkDerivation
function generates a build directory (and corresponding build.conf
) based on the sources provided. All commands supplied in the buildPhase
and installPhase
are executed from within this directory. Additionally, all environment variables available in the Nix shell are available here. Keep in mind that, unlike the shell environment, internet access is not available when building Nix derivations. All downloads (e.g., ports) must be prepared in advance by Nix to protect reproducibility.
The buildPhase
should include all commands required to produce the desired artifacts. For example, the template runs a single Genode runscript to produce a system image.
The installPhase
immediately follows the buildPhase
and should copy the desired artifact(s) to the output directory stored in the $out
environment variable.
. . .
genodeEnv.mkDerivation {
name = "my-package";
buildInputs = with genode-utils.packages.${system}; [
grub2
nova
];
repos = [
./.
];
buildPhase = ''
make run/hello
'';
installPhase = ''
cp var/run/hello.iso $out
'';
}
. . .
Nix flakes make updating the external dependencies of your project very simple. Each of the inputs to your flake is "locked" at a specific commit hash by flake.lock
. To advance all inputs to the latest commit in the branch they are following, run the following command.
nix flake update --commit-lock-file
Note that the --commit-lock-file
is optional, but provides a nice commit message precisely describing the changes that were made. Keeping flake.lock
updates in separate commits also makes it easy to revert if an update causes breakage.
To update a single input (e.g., nixpkgs
), run the following command.
nix flake lock --update-input nixpkgs --commit-lock-file
Again, the --commit-lock-file
is optional.