Incorporating into your project
This page describes the CMake-based build system in detail, with sufficient information for integrating it into new projects. There are a few different pieces that can be fit together in different ways depending on your project’s needs and desired customisation. This is reflected in the split of CMake files spread across several repositories.
Basic structure
The build system is in two pieces. One piece is in the seL4 kernel repository, which contains the compiler toolchain and flags settings as well as helpers for generating configurations. The other piece is in seL4_tools/cmake-tool, which contains helpers for combining libraries and binaries into a final system image (along with the kernel).
This structure means that the kernel is completely responsible for building itself, but exports the settings and binaries for use by the rest of the build system.
The cmake-tool
directory has the following files of interest:
default-CMakeLists.txt
: An exampleCMakeLists.txt
file, which could be used as theCMakeLists.txt
file in the top-level directory of a project. Simply, this file includesall.cmake
, under the assumption of a directory structure where thecmake-tool
repository is in a directory namedtools
. To use this file, project manifests are expected to create a symbolic link to this file, namedCMakeLists.txt
, at the top-level project directory.all.cmake
: A wrapper that includesbase.cmake
,projects.cmake
andconfiguration.cmake
. This file can be used by projects which do not alter these three files.base.cmake
: Constructs the basic build targets (kernel
,libsel4
, andelfloader-tool
), in addition to basic compilation flags and helper routines, required to build an seL4 project, and can be used as a base for further targets in a project through theadd_subdirectory
routine or otherwise.projects.cmake
: Adds build targets throughadd_subdirectory
assuming a default project layout. Essentially it adds anyCMakeLists.txt
files it finds in any subdirectories of the projects directory.configuration.cmake
: Provides a target for a library calledConfiguration
that emulates the legacyautoconf.h
header. Since theautoconf.h
header contained configuration variables for the entire project this rule needs to come after all other targets and scripts which add to the configuration space.common.cmake
: File included bybase.cmake
with some generic helper routines.flags.cmake
: File included bybase.cmake
which sets up build flags and linker invocations.init-build.sh
: A shell script which performs the initial configuration and generation for a new CMake build directory.helpers/*
: Helper functions that are commonly imported bycommon.cmake
Kernel directory
The file base.cmake
assumes that the seL4 kernel is in a specific location. Consider the following example:
awesome_system/
├── kernel/
│ └── CMakeLists.txt
├── projects/
│ ├── awesome_system/
│ │ └── CMakeLists.txt
│ └── seL4_libs/
│ └── CMakeLists.txt
├── tools/
│ └── cmake-tool/
│ ├── base.cmake
│ ├── all.cmake
│ └── default-CMakeLists.txt
├── .repo/
└── CMakeLists.txt -> tools/cmake-tool/default-CMakeLists.txt
When awesome_system/
is used as the root source directory to initialise a CMake build directory
and tools/cmake-tool/all.cmake
is used, base.cmake
expects the kernel to be at
awesome_system/kernel
.
The kernel can be placed in a different location, as described below.
awesome_system/
├── seL4/
│ └── CMakeLists.txt
├── projects/
│ ├── awesome_system/
│ │ └── CMakeLists.txt
│ └── seL4_libs/
│ └── CMakeLists.txt
├── tools/
│ └── cmake-tool/
│ ├── base.cmake
│ ├── all.cmake
│ └── default-CMakeLists.txt
├── .repo/
└── CMakeLists.txt -> tools/cmake-tool/default-CMakeLists.txt
For the example above, where the kernel is in a directory called seL4
, the default kernel location can be overriden when invoking cmake
with -DKERNEL_PATH=seL4
.
Advanced structures
Other project layouts can be used. Consider the following example:
awesome_system/
├── seL4/
│ └── CMakeLists.txt
├── awesome/
│ └── CMakeLists.txt
├── seL4_libs/
│ └── CMakeLists.txt
├── buildsystem/
│ └── cmake-tool/
│ ├── base.cmake
│ ├── all.cmake
│ └── default-CMakeLists.txt
└── .repo/
The example above departs from the default in the following ways:
- no
CMakeLists.txt
file in the root directory, tools
directory has been renamed tobuildsystem
,kernel
directory has been renamed toseL4
,- and the
projects
directory is omitted.
We now describe how to achieve such a project structure:
To place the CMakeLists.txt
in awesome_system/awesome
directory then initialise CMake,
assuming a build directory that is also in the awesome_system
directory, do something like:
sel4@host:~/awesome_directory$ cmake -DCROSS_COMPILER_PREFIX=toolchain-prefix -DCMAKE_TOOLCHAIN_FILE=../seL4/gcc.cmake -DKERNEL_PATH=../seL4 -G Ninja ../awesome
Importantly, the path for CMAKE_TOOLCHAIN_FILE
is resolved immediately by CMake, and so is
relative to the build directory, whereas the KERNEL_PATH
is resolved whilst processing awesome_system/awesome/CMakeLists.txt
and is relative to that directory.
The contents of awesome_system/awesome/CMakeLists.txt
would be something like:
cmake_minimum_required(VERSION 3.7.2)
include(../buildsystem/cmake-tool/base.cmake)
add_subdirectory(../seL4_libs seL4_libs)
include(../buildsystem/cmake-tool/configuration.cmake)
This looks pretty much like all.cmake
except that we do not include projects.cmake
as we do not have a
projects folder. projects.cmake
would be redundant to include, as it would not resolve any files.
all.cmake
cannot be included as we need to include specific subdirectories (in the example seL4_libs
)
between setting up the base flags and environment and finalising the Configuration library.
We needed to give an explicit build directory (the second argument in add_subdirectory
) as we are giving
a directory that is not a subdirectory of the root source directory.
For simplicity, the kernel path can be encoded directly into the projects top-level CMakeLists.txt
. To
achieve this the following line:
set(KERNEL_PATH ../seL4)
should be included before
include(../buildsystem/cmake-tool/base.cmake)
in awesome_system/awesome/CMakeLists.txt
, thus removing the need for -DKERNEL_PATH
in the cmake
invocation.
Configuration
For compatibility with the legacy build system, various helpers and systems exist in order to achieve the following:
- Automate configuration variables that appear in the
cmake-gui
with various kinds of dependencies. - Generate C-style configuration headers that declare these variables in format similar to the legacy build system.
- Generate
autoconf.h
headers so legacy code using#include <autoconf.h>
works.
The following fragment of CMake script demonstrates how these three things fit together:
set(configure_string "")
config_option(EnableAwesome HAVE_AWESOME "Makes library awesome" DEFAULT ON)
add_config_library(MyLibrary "${configure_string}")
generate_autoconf(MyLibraryAutoconf "MyLibrary")
target_link_libraries(MyLibrary PUBLIC MyLibrary_Config)
target_link_libraries(LegacyApplication PRIVATE MyLibrary MyLibraryAutoconf)
In the above example, line by line:
set(configure_string "")
: Initialiseconfigure_string
as blank, as variousconfig_*
helpers automatically append to this variable.config_option(EnableAwesome HAVE_AWESOME "Makes library awesome" DEFAULT ON)
: Declare a configuration variable which appears in CMake scripts and thecmake-gui
asEnableAwesome
, while appearing in C headers asCONFIG_HAVE_AWESOME
.add_config_library(MyLibrary "${configure_string}")
: Generate aMyLibrary_Config
target, which is an interface library that has a generated C header based on the configuration string. Also addMyLibrary
to a global list of configuration libraries, which can be used to generate a library containing contains “all the configurations in the system” (autoconf.h
in the legacy build system).generate_autoconf(MyLibraryAutoconf "MyLibrary")
: Generates aMyLibraryAutoconf
target, which is an interface library that depends uponMyLibrary_Config
, and provides anautoconf.h
file including the configuration header fromMyLibrary_Config
.target_link_libraries(MyLibrary PUBLIC MyLibrary_Config)
: AllowsMyLibrary
to#include
the generated configuration header by doing#include <MyLibrary/gen_config.h>
target_link_libraries(LegacyApplication PRIVATE MyLibrary MyLibraryAutoconf)
AllowsLegacyApplication
to#include <autoconf.h>
fromMyLibraryAutoconf
. Theautoconf.h
in this case will contain#include <MyLibrary/gen_config.h>
.
For more details of the different config_*
helpers read the comments on the functions in kernel/tools/helpers.cmake.
Helper functions
Several CMake functions exist for reuse in seL4 projects, which we now describe.
Kernel provided helpers
All of the helper functions described in the above section are provided in tools/helpers.cmake
in the seL4 repository. Other functions in this file are only useful for the kernel build itself.
cmake-tool
provided helpers
These helper functions are provided for user-level projects, in common.cmake
and
all the files in helpers/
. Notable functions are:
DeclareRootserver(rootserver_target)
: Declares a CMake executable,rootserver_target
, as the root server for the system. This can only be used once in a project and does the following:- changes build flags for the target,
- creates necessary extra targets for chain loading,
- creates the
rootserver_image
target which will create the final binary images inimages
.
MakeCPIO
: Declares rules to create a linkable CPIO archive from a list of input files.GenerateSimulateScript
: Creates a target calledsimulate_gen
which will generate a./simulate
shell script in the build directory for simulating the project on QEMU if the target platform is supported. An application is responsible for ensuring that the system configuration can be simulated if it uses this function. Other functions are provided such asSetSimulationScriptProperty
to allow the application’s CMake scripts to customise the simulation command generated.ApplyCommonSimulationSettings
: Attempts to change the kernel system configuration to disable features that are not compatible with simulation.ApplyCommonReleaseVerificationSettings(release, verification)
: Sets flags for different combinations of ‘release’ (performance optimized builds) and ‘verification’ (verification friendly features) builds. Please see [/Developing/Building/Using#Meta-configuration-options] for more detail on these options.
Other provided helpers
Projects such as Camkes, the Camkes x86 VMM, and Rumprun may provide additional helper functions
to allow applications to configure themselves. Generally helper scripts will be called some variant
of helpers.cmake
, and should be included in any CMake scripts that use them.