Skip to content

BUILDING

Matthias Lange edited this page Oct 15, 2024 · 16 revisions

Building L4Re

Building an L4Re system from scratch involves several Git repositories and multiple steps described in this document.

Prerequisities

Depending on your host system, you might need to install some prerequisities.

On Debian 12 (Bookworm), make sure you have the required packages installed together with their dependencies by running the following command with sufficient privileges:

[somedir] $ apt-get install git make binutils liburi-perl libpar-packer-perl libgit-repository-perl libxml-parser-perl gcc g++ libc6-dev-i386 libncurses-dev qemu-system xorriso mtools flex bison pkg-config gawk device-tree-compiler dialog wget doxygen graphviz

On top of a fresh Fedora 27 install, you will need the following packages and their dependencies:

[somedir] $ dnf install perl-URI perl-PAR-Packer perl-Git-Repository-Plugin-AUTOLOAD perl-CPAN perl-Test perl-Text-Balanced gcc gcc-c++ glibc-devel.i686 ncurses-devel xorriso flex bison pkgconf-pkg-config gawk dtc
[somedir] $ cpan install XML::Mini::Document

On Arch Linux, the following packages need to be installed:

[somedir] $ pacman -S --needed base-devel dtc lib32-gcc-libs qemu qemu-arch-extra mtools

Additionally, these packages need to be installed from the AUR by a method of your choice:

[somedir] $ yay -S perl-par-packer perl-git-repository perl-xml-mini perl-uri

Getting and installing ham

L4Re is composed of several loosely coupled Git repositories. While it is theoretically possible to manage them individually using Git alone, it is recommended to use ham to manage the whole set at once.

[somedir] $ git clone https://github.com/kernkonzept/ham.git
[somedir] $ cd ham
[somedir/ham] $ make

Make sure to include ham in your PATH.

Getting the L4Re sources using ham

Use ham to get the L4Re project manifest and all its constituent repositories:

[somedir/ham] $ cd ..
[somedir] $ ham init -u https://github.com/kernkonzept/manifest.git
[somedir] $ ham sync

If ham sync is terminated early or fails to sync refer to the troubleshooting information.

Building L4Re

When building L4Re for the first time, you first need to create and configure a build directory:

[somedir] cd l4
[somedir/l4] $ make B=../build-amd64
[somedir/l4] $ cd ../build-amd64
[somedir/build-amd64] $ make oldconfig

Note that amd64 / x86_64 is the default, so no interactive selection is necessary. If you want to check, please use make config. Also note that the build directory can be arbitrary. build-amd64 is used as an example here.

The build directory is now ready and you can build the L4Re binaries:

[somedir/build-amd64] $ make           # Optionally use -j X to make the build parallel

The release L4Re binaries reside in the bin subdirectory of the build directory. For the amd64 configuration, this is bin/amd64_gen/l4f:

[somedir/build-amd64] $ file bin/amd64_gen/l4f/hello
bin/amd64_gen/l4f/hello: bin/amd64_K8/l4f/hello: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, BuildID[sha1]=..., with debug_info, not stripped

Building the L4Re Microkernel

For running the L4Re binaries, you are going to need the L4Re Microkernel microkernel, which is cloned by ham as part of the L4Re manifest.

Create and configure the Fiasco build directory:

[somedir/build-amd64] cd ../fiasco
[somedir/fiasco] $ make B=../build-fiasco-amd64
[somedir/fiasco] $ cd ../build-fiasco-amd64
[somedir/build-fiasco-amd64] $ make oldconfig # amd64 is the default architecture

The microkernel has some more feature to choose. You might check them with make config.

And finally, build the microkernel itself:

[somedir/build-fiasco-amd64] $ make           # Optionally use -j X to make the build parallel

Like in the L4Re case above, the build directory is created and configured only once. The resulting microkernel binary is called fiasco.

Running the Hello world! program

Now that you have sucessfully built Fiasco and L4Re, it is time to verify that they were built correctly by running a simple demo scenario with a sample program called hello:

[somedir/build-fiasco-amd64] cd ../build-amd64
[somedir/build-amd64] $ make E=hello qemu MODULE_SEARCH_PATH="${PWD}/../build-fiasco-amd64"

This will run the scenario in QEMU without creating any bootable images. After a short while, you should see the message "Hello World!" printed in 1-second intervals on the virtual QEMU screen.

If you prefer having a bootable ISO instead, you can generate one like this:

[somedir/build-amd64] $ make E=hello grub2iso MODULE_SEARCH_PATH="${PWD}/../build-fiasco-amd64"

The generated ISO image can be found in the images subdirectory.

Making life easier with Makeconf.boot and Makeconf.local

If you copy somedir/l4/conf/Makeconf.boot.example to somedir/l4/conf/Makeconf.boot and point the FIASCO_PATH-amd64 variable in there to your microkernel build directory, you wouldn't have to specify it in the MODULE_SEARCH_PATH environment variable on the command line everytime.

Makeconf.boot is also the place to tune various QEMU and platform-specific options.

In a similar way, you can create Makeconf.local in your build directory and define the variables used during the configuration phase (e.g. the cross-compiler configuration, see below) there.

Cross-compiling for ARM, ARM64 and RISC-V

If you are going to cross-compile L4Re for ARM, ARM64 (aarch64) or RISC-V, you'll need to install the respective QEMU packages for the target platforms and cross-compilers.

Your distribution most likely provides some cross-compiler packages for selected platforms. Debian cross-compilers (packaged in g++-arm-linux-gnueabihf, g++-aarch64-linux-gnu, g++-riscv64-linux-gnu) have been known to work with L4Re.

The cross-compilation of L4Re and Fiasco is similar to the normal build:

[somedir/l4] $ make B=../build-arm64
[somedir/l4] $ cd ../build-arm64

When cross-compiling, you have to specify the prefix of the cross-tools you wish to use in the CROSS_COMPILE variable at some point before the config phase.

For example, when cross-compiling for the 64-bit ARM Virt QEMU platform, you need to specify the CROSS_COMPILE variable in a file called Makeconf.local. Adjustments might be necessary for different cross-compilers and platforms:

[somedir/build-arm] $ echo "CROSS_COMPILE:=aarch64-linux-gnu-" > Makeconf.local
[somedir/build-arm] $ make config    # Select ARM architecture, Cortex-A57 and QEMU virt platform
[somedir/build-arm] $ make

Alternatively, you can define the CROSS_COMPILE variable on the command line.

In both cases, don't forget to configure the system for the ARM64 architecture.

Cross-compiling the microkernel is analogous. Make sure to unselect the Virtualization option in this case:

[somedir/build-arm] $ cd ../fiasco
[somedir/fiasco] $ make B=../build-fiasco-arm64
[somedir/fiasco] $ cd ../build-fiasco-arm64
[somedir/build-fiasco-arm64] $ echo "CROSS_COMPILE:=aarch64-linux-gnu-" > Makeconf.local
[somedir/build-fiasco-arm64] $ make config    # Select ARM processor family as Architecture, QEMU ARM Virtual Platform as Platform, ARM Cortex-A57 CPU as CPU
[somedir/build-fiasco-arm] $ make

When all is built, run the hello scenario in QEMU (assuming qemu-system-aarch64 is installed on the system):

[somedir/build-fiasco-arm] $ cd ../build-arm
[somedir/build-arm64] $ make E=hello qemu MODULE_SEARCH_PATH="${PWD}/../build-fiasco-arm64" PLATFORM_TYPE=arm_virt

Note that besides MODULE_SEARCH_PATH, also QEMU_OPTIONS and PLATFORM_TYPE can be conveniently specified in somedir/l4/conf/Makeconf.boot.

Troubleshooting

Building the microkernel and L4Re user-level is a procedure complex enough to offer many opportunities for things to go wrong. Here are the most common issues and their causes:

Recovering from ham sync errors

If ham sync is terminated early using Ctrl-C or encounters network errors such as the following an incomplete manifest may have been synced.

mk: fatal: The remote end hung up unexpectedly
mk: fatal: early EOF
mk: fatal: index-pack failed

It is usually best to start again with an empty directory. Alternatively, it may be possible to selectively force sync some packages listed in .ham/manifest.xml:

[somedir] $ ham sync --force-local-update <manifest package name>

If network issues are suspected try:

[somedir] $ ham sync --max-connections=1

Missing top-level make file

If the ham sync operation was incomplete the mk package may be missing. In this case it's best to restart ham sync from an empty directory. Running make in the top-level directory results in this error indicating the top-level Makefile is missing:

make: *** No targets specified and no makefile found.  Stop.

Missing multilib

If you get the following error when creating a build directory on a 64-bit host, make sure that multilib (or libraries supplementing it, e.g. glibc-devel.i686 on Fedora) are installed:

/usr/include/linux/errno.h:1:23: fatal error: asm/errno.h: No such file or directory
#include <asm/errno.h>
                      ^
compilation terminated.

Forgetting to set the architecture during make config before cross-compilation

If you forget to set the respective architecture during the configuration step before cross-compilation, you may get failures that look like:

arm-linux-gnueabihf-gcc: error: unrecognized command line option ‘-m32’
Makefile:372: recipe for target 'Makeconf.bid.local-internal-names' failed
make[5]: *** [Makeconf.bid.local-internal-names] Error 1