Home

Awesome

ReaverOS

A new iteration, from "scratch", of a µkernel-based operating system for 64-bit architectures. Previous iteration can be found here: https://github.com/griwes/reaveros-iteration1.

Building ReaverOS

Dependencies

ReaverOS' build system bootstraps most tools that it uses as build tools, but not all the tools the tools it bootstraps depend on themselves. That being said, we are trying to keep the dependencies of the build system to a minimum. Currently, those dependencies are:

On a recent apt-based systems, the following command should fulfill the dependencies:

apt install build-essential automake cmake git python3 bison flex libssl-dev

Build considerations

ReaverOS builds the full toolchain that it uses for all builds internally, at versions fixed as git tags. This means that to build ReaverOS, you need internet access to fetch the repositories for the entire toolchain.

This also means that an initial build using a given toolchain will take a long time, because it will build full LLVM. Two docker images containing pre-built binaries are available:

The images expect the root directory of the git repository mounted in /reaveros. A possible way to achieve this is to:

git clone https://github.com/griwes/reaveros
docker run -v $(pwd):/reaveros -it <image>
# <image> is one of the URLs listed above

Inside the container, cd /build; from there, you can run all the normal ReaverOS build targets, as described below. To move the images out of the container (to be able to run them with QEMU, for instance), you can create a directory in your checkout directory and move appropriate files from within the build directory into that directory:

cd /reaveros
mkdir build-results
cd /build
make all-images
cp install/images/uefi-efipart-amd64.img /reaveros/build-results

Alternatively, you can create another docker volume, with -v, and copy the results there.

Keep in mind that if you terminate the docker container, you will need to rebuild the ReaverOS code itself - but the build should be fairly quick regardless.

The docker images are rebuilt daily, but unless a toolchain version changes, it should not affect them. However, if you do a git pull, and there are changes to the toolchain versions between your old copy of the repository and upstream, it is recommended to also restart the docker container and do docker pull on the image you are using, to get the latest versions of the prebuilt toolchain.

Configuration options

The build uses the normal CMake C and C++ compiler heuristics to detect what compiler to use for building all the various tools used during the build. Additionally, the following options are exposed:

Build targets

ReaverOS' build system doesn't add any targets as a dependency of all, due to the sheer amount of targets an eventual full configuration will require. Instead, it provides more fine grained aggregate targets. There is too many of those to list them here; you can run make help to see them all. They should be self explanatory, but to name a few as an example:

Some of the aggregate targets are not useful and are only generated to allow for code simplicity in the functions creating them; for instance, all-hosted-loaders is not a reasonable target to run, because bootloaders only use freestanding environments.

There are also targets for the specific components of the build, for instance:

There's one more group of targets that are of note - the prune targets. All toolchain targets have an associated prune target, and there also exists an aggregate all-toolchain-prune target. Their role is to remove the source and build directories of a given (or all) toolchain subprojects, to reduce the build directory size; since all the toolchain installs into subdirectories of install/toolchain, the source and build directories aren't needed to build all of ReaverOS targets.

Do keep in mind that this means that if a version of a pruned toolchain changes, you will need to re-download the sources, re-configure the project, and rebuild it fully; since the compilers used by ReaverOS can (and will) take a long time to compile, you should be very careful of pruning a toolchain if you disabled build caching (see REAVEROS_USE_CACHE above), built enough files to have your cache evict the previous stored build results, and do not wish to possibly wait for full LLVM builds to finish whenever you pull the main branch.

Running the OS (as far as it goes, at least)

This last mentioned target - image-uefi-efipart-amd64 - will create a file containing a FAT filesystem image that includes the UEFI bootloader for the amd64 architecture. If you install QEMU and OVMF, you can then run it and see what happens with a command like this (this is the exact command I have been using to test at the time of these words being written on a Debian sid):

qemu-system-x86_64 -bios /usr/share/ovmf/OVMF.fd -drive format=raw,file=install/images/uefi-efipart-amd64.img -monitor stdio -serial file:/dev/stdout -cpu qemu64,+sse3,+sse4.1,+sse4.2 -m 2048 -smp 4 -vga std -M q35 -global hpet.msi=on -netdev user,id=net0 -device e1000e,romfile=,netdev=net0

Platform requirements:

  1. UEFI.
  2. HPET w/ FSB interrupt delivery; this is achieved in QEMU with -global hpet.msi=on.

Unit tests

For testing, there's two kinds of interesting CMake targets:

After the tests for a specific configuration have been built, they can be run with ctest. By default, all enabled tests for all enabled components for all enabled architectures are run. The set of tests to be run can be controlled using test labels; to see a list of labels available on a given configuration, run ctest --print-labels. To run tests matching a specific label, use ctest -L. See the ctest documentation for further instructions.

For convenience, an additional target - run-tests - is exposed. This target is equivalent to building the all-build-tests target, followed by running ctest with no arguments.