1<!-- 2 Copyright 2020, Data61, CSIRO (ABN 41 687 119 230) 3 4 SPDX-License-Identifier: BSD-2-Clause 5--> 6 7# CMake seL4 Build System 8 9> Description of the CMake based build system for building the seL4 kernel and seL4 based projects 10 11## Using projects 12 13This section is a small tutorial on how to interact with and build a project that is using this build system. 14If you are developing a project then should read the 'using in a project' section. 15 16### CMake basics 17 18For a complete guide to CMake you can read the [extensive documentation](https://cmake.org/cmake/help/latest/), 19but for the purposes here we will assume a particular workflow with CMake involving out of tree builds. 20 21CMake is not itself a build tool, but rather is a build generator. This means that it generates build scripts, 22typically Makefiles or Ninja scripts, which will be used either by a tool like GNU Make or Ninja to perform 23the actual build. 24 25#### Pre-requisites 26 27It is assumed that 28 29 * CMake of an appropriate version is installed 30 * You are using the Ninja CMake generator 31 * You understand how to checkout projects using the repo tool as described on the 32 [Getting started](https://docs.sel4.systems/GettingStarted) page 33 34#### Basic build initialisation 35 36Assuming you are in the root directory of a seL4-based project you should start with 37 38```sh 39mkdir build 40cd build 41``` 42 43Then initialise CMake with something like 44 45```sh 46cmake -DCROSS_COMPILER_PREFIX=arm-linux-gnueabi- -DCMAKE_TOOLCHAIN_FILE=../kernel/gcc.cmake -G Ninja .. 47``` 48 49Breaking down what each component means 50 51 * `-D` means we are defining a variable in the form `X=Y` 52 * `CROSS_COMPILER_PREFIX` is a variable that will be used later on and contains the prefix for the gcc based 53 toolchain we want to use. You cannot change your toolchain once you have initialised a build directory 54 * `CMAKE_TOOLCHAIN_FILE` is variable understood by CMake and tells it to load the specified file as a 55 'toolchain' file. A toolchain file is able to setup the C compiler, linker etc that should be used. In this 56 case we assume a typical project layout with the seL4 kernel in a 'kernel' directory at the top level. The 57 '[gcc.cmake](https://github.com/seL4/seL4/blob/master/gcc.cmake)' file in it sets up C compilers and linkers 58 using the previously supplied `CROSS_COMPILER_PREFIX` 59 * `-G Ninja` tells CMake that we want to generate Ninja build scripts as opposed to GNU Makefiles. Currently 60 only Ninja scripts are supported by parts of the kernel 61 * `..` is the path to the top level `CMakeLists.txt` file that describes this project, generally this is 62 placed in the root directory so this parameter is typically `..`, but could be any path 63 64If all goes well you should now be able to build by doing 65 66```sh 67ninja 68``` 69 70And the resulting binaries will be placed in the `images/` directory 71 72### Configuration 73 74Many projects will have some degree of customisation available to them. Assuming a build directory that has been 75initialised with CMake you can do either 76 77```sh 78ccmake .. 79``` 80 81for a ncurses based configuration editor or 82 83```sh 84cmake-gui .. 85``` 86 87for a graphical configuration editor. In both invocations the path `..` should be the same path as was used in the original `cmake` invocation. 88 89CMake itself has two different kinds of options: 90 91 * Booleans: These are either `ON` or `OFF` 92 * Strings: These can be set to any value, although they may be restricted to a set of values by whoever wrote the project. 93 94String options can have 'hints' given to them that they should only take on one of several fixed values. The 95CMake configuration editors will respect these and provide a radio selection. 96 97As you change configuration options the CMake scripts for the project are not continuously rerun. You can explicitly 98rerun by telling it to '(c)onfigure'. This may result in additional options appearing in the configuration editor, 99or some options being removed, depending on what their dependencies where. For example if there is option `A` that 100is dependent on option `B` being true, and you change `B` to true, `A` will not show up until you (c)onfigure and 101the CMake files are reprocessed. 102 103When you are done changing options you can either '(g)enerate and exit' or '(q)uit without generation'. If you 104quit without generating then your changes will be discarded, you may do this at any time. You will only be 105allowed to generate if you run (c)onfigure after doing any changes and CMake believes your configuration has 106reached a fixed point. 107 108After changing any options and generating call 109 110```sh 111ninja 112``` 113 114to rebuild the project. 115 116#### Initial configurations 117 118If a project supports different configurations they will typically provide some configuration `.cmake` files to 119allow you to initialise the project in a certain way. Configurations are provided when initialising the build 120directory by passing `-C <file>` to `cmake`. For example given some typical project structure the `cmake` 121in the last example could become 122 123```sh 124cmake -C../projects/awesome_project/configs/arm_debug.cmake -DCROSS_COMPILER_PREFIX=arm-linux-gnueabi- -DCMAKE_TOOLCHAIN_FILE=../kernel/gcc.cmake -G Ninja .. 125``` 126 127Note that multiple `-C` options can be given, although if they try and set the same options only one of the 128settings will actually get used. This means in the previous example we might have two different configuration 129files for `arm.cmake` and `x86.cmake`, and then two other files for `debug.cmake` and `release.cmake`. We could 130now combine `arm.cmake` with either `debug.cmake` or `release.cmake`, similarly with `x86.cmake`. For example 131 132```sh 133cmake -C../projects/awesome_project/configs/arm.cmake -C../projects/awesome_project/configs/debug.cmake -DCROSS_COMPILER_PREFIX=arm-linux-gnueabi- -DCMAKE_TOOLCHAIN_FILE=../kernel/gcc.cmake -G Ninja .. 134``` 135 136Nothing stops you from trying to initialise with both `arm.cmake` and `x86.cmake`, but since they are probably 137setting some of the same options only one will actually take effect. If the project has multiple configuration 138files you should check which can be composed. 139 140#### [sel4test](https://github.com/seL4/sel4test) example 141 142In the previous examples we ended up with some relatively long `cmake` invocations. These can be aliased/scripted 143in various ways. One such example is in the [sel4test](https://github.com/seL4/sel4test) project, which has 144a script for automatically picking a toolchain and composing configuration files. 145 146Assuming sel4test is correctly checked out and you're in the root directory you would do something like 147 148```sh 149./projects/sel4test/configure ia32 debug simulation 150``` 151 152This will create a `build_ia32_debug_simulation` directory and initialise it with the `ia32.cmake`, `debug.cmake`, 153`simulation.cmake` and `sel4test.cmake` files from the `projects/sel4test/configs` directory. It will also 154select the system `gcc` as the cross compiler under the assumption you are building on an x86 machine. 155 156If you configured with something like 157 158```sh 159./projects/sel4test/configure sabre verification 160``` 161 162It will create a `build_sabre_verification` directory and initialise with `sabre.cmake`, `verification.cmake`, 163and `sel4test.cmake`. In this case it will also set the cross compiler to `arm-linux-gnueabi-` 164 165Not all projects have the configuration complexity of sel4test, but this serves as an example of how a given 166project might simplify its configuration process. 167 168#### CMAKE_BUILD_TYPE 169 170The `CMAKE_BUILD_TYPE` option is an option that will appear in the CMake configuration editors that is not 171defined by a project, but is rather defined by CMake itself. This option configures the kind of build to do; 172release, debug, release with debug information, etc. Note that the seL4 kernel ignores this setting as due 173to the way the kernel has to be built it side steps many of the CMake systems. 174 175## Using in a project 176 177This section describes how pieces of the build system fit together and how you might use it in a new project. 178There are a few different pieces that can be fit together in different ways depending on your project's needs 179and desired customisation. This is reflected in the split of files in the cmake-tool directory. 180 181### Basic structure 182 183The build system here is in two pieces. One piece is in the seL4 kernel repository, which has all of the basic 184compiler toolchain and flags settings as well as helpers for generating configurations. The other piece is in seL4_tools/cmake-tool, 185which has helpers for putting libraries and binaries together into a final system image (along with the kernel). 186 187This structure means that the kernel is completely responsible for building itself, but exports the settings 188it uses and the binaries it creates so that the rest of this build system can use it and build the final image. 189 190The cmake-tool directory has the following files: 191 192 * `README.md` What you are reading 193 * `default-CMakeLists.txt` An example CMakeLists.txt file that you could use as the CMakeLists.txt file in 194 your top level directory. All this does is include `all.cmake`, under the assumption of a directory structure 195 where this repository is in a directory named `tools`. It is the intention that a projects manifest xml 196 would symlink this to the top level and call it CMakeLists.txt 197 * `all.cmake` Helper file that is just a wrapper around including `base.cmake`, `projects.cmake` and 198 `configuration.cmake` This serves convenience for projects that just want to include those three files 199 for a default configuration without making any changes between them 200 * `base.cmake` Includes the kernel as a subdirectory, includes some files of common helper routines, sets up 201 the basic compilation flags as exported by the kernel and then adds libsel4 and the elfloader-tool as 202 buildable targets. This file essentially sets up the basic build targets (kernel, libsel4, elfloader) and 203 flags after which you could start defining your own build targets through `add_subdirectory` or otherwise 204 * `projects.cmake` Adds default build targets through `add_subdirectory` assuming a default project layout. 205 Essentially it adds any CMakeLists.txt files it finds in any subdirectories of the projects directory 206 * `configuration.cmake` Provides a target for a library called `Configuration` that emulates the legacy 207 `autoconf.h` header. Since the `autoconf.h` header contained configuration variables for the *entire* project 208 this rule needs to come after all other targets and scripts that might add to the configuration space. 209 * `common.cmake` File included by `base.cmake` that has some generic helper routines. There should be no need 210 to include this file directly 211 * `flags.cmake` Sets up build flags and linker invocations based off the exported kernel flags. This is included 212 by `base.cmake` and there should be no need to include this file directly 213 * `init-build.sh` shell script that performs the initial configuration and generation for a new CMake build directory. 214 * `helpers/*` helper functions that are commonly imported by `common.cmake` 215 216### Kernel directory 217 218For simplicity of the common case `base.cmake` defaults to assuming that the seL4 kernel is in directory called 219`kernel` that is in the same directory of wherever `base.cmake` is included from. This means that if you have a 220directory structure like 221 222```none 223awesome_system/ 224��������� kernel/ 225��� ��������� CMakeLists.txt 226��������� projects/ 227��� ��������� awesome_system/ 228��� ��� ��������� CMakeLists.txt 229��� ��������� seL4_libs/ 230��� ��������� CMakeLists.txt 231��������� tools/ 232��� ��������� cmake-tool/ 233��� ��������� base.cmake 234��� ��������� all.cmake 235��� ��������� default-CMakeLists.txt 236��������� .repo/ 237��������� CMakeLists.txt -> tools/cmake-tool/default-CMakeLists.txt 238``` 239 240Then when `awesome_system/` is used used as the root source directory to initialise a CMake build directory 241the `tools/cmake-tool/all.cmake` file is included, that then includes `base.cmake`, which will then look for 242`awesome_system/kernel` as the directory of the kernel. 243 244If you decided to put the kernel into a differently named directory, for example: 245 246```none 247awesome_system/ 248��������� seL4/ 249��� ��������� CMakeLists.txt 250��������� projects/ 251��� ��������� awesome_system/ 252��� ��� ��������� CMakeLists.txt 253��� ��������� seL4_libs/ 254��� ��������� CMakeLists.txt 255��������� tools/ 256��� ��������� cmake-tool/ 257��� ��������� base.cmake 258��� ��������� all.cmake 259��� ��������� default-CMakeLists.txt 260��������� .repo/ 261��������� CMakeLists.txt -> tools/cmake-tool/default-CMakeLists.txt 262``` 263 264Then you could override the default kernel location by passing `-DKERNEL_PATH=seL4` when first invoking `cmake` 265 266### Advanced structures 267 268Suppose you wanted to completely go away from the normal directory structure and instead have something like 269 270```none 271awesome_system/ 272��������� seL4/ 273��� ��������� CMakeLists.txt 274��������� awesome/ 275��� ��������� CMakeLists.txt 276��������� seL4_libs/ 277��� ��������� CMakeLists.txt 278��������� buildsystem/ 279��� ��������� cmake-tool/ 280��� ��������� base.cmake 281��� ��������� all.cmake 282��� ��������� default-CMakeLists.txt 283��������� .repo/ 284``` 285 286In this example there is 287 288 * No `CMakeLists.txt` file in the root directory 289 * `tools` directory has been renamed 290 * `kernel` directory has been renamed 291 * No `projects` directory 292 293If we want the `CMakeLists.txt` in the `awesome_system/awesome` directory then would initialise CMake, 294assuming a build directory that is also in the `awesome_system` directory, do something like 295 296```sh 297cmake -DCROSS_COMPILER_PREFIX=toolchain-prefix -DCMAKE_TOOLCHAIN_FILE=../seL4/gcc.cmake -DKERNEL_PATH=../seL4 -G Ninja ../awesome 298``` 299 300What is important here is that the path for `CMAKE_TOOLCHAIN_FILE` is resolved immediately by CMake, and so is 301relative to the build directory, where as the `KERNEL_PATH` is resolved whilst processing `awesome_system/awesome/CMakeLists.txt` 302and so is relative to that directory. 303 304The contents of `awesome_system/awesome/CMakeLists.txt` would be something like 305 306```cmake 307cmake_minimum_required(VERSION 3.7.2) 308include(../buildsystem/cmake-tool/base.cmake) 309add_subdirectory(../seL4_libs seL4_libs) 310include(../buildsystem/cmake-tool/configuration.cmake) 311``` 312 313This looks pretty much like `all.cmake` except that we do not include `projects.cmake` as we do not have a projects 314folder. It wouldn't be harmful to include it since it would just resolve no files, but is redundant. We cannot 315simply include `all.cmake` was we need to include our subdirectories (in this case just seL4_libs) between setting 316up the base flags and environment and finalising the Configuration library. We needed to give an explicit build 317directory (the second argument in `add_subdirectory`) as we are giving a directory that is not a subdirectory of 318the root source directory. 319 320For simplicity, the kernel path could be encoded directly into the projects CMakeLists.txt, so you could 321add 322 323```cmake 324set(KERNEL_PATH ../seL4) 325``` 326 327before 328 329```cmake 330include(../buildsystem/cmake-tool/base.cmake) 331``` 332 333in `awesome_system/awesome/CMakeLists.txt`, removing the need for `-DKERNEL_PATH` in the `cmake` invocation. 334 335### Configuration 336 337To provide a configuration system that was compatible with how the previous build system provided configuration 338various helpers and systems exist to: 339 340 * Automate configuration variables that appear in the cmake-gui with various kinds of dependencies 341 * Generate C configuration headers that declare these variables in format similar to what Kconfig did 342 * Generate 'autoconf.h' headers so old code that does `#include <autoconf.h>` still work 343 344A simple fragment of a CMake script that demonstrates how these three things fit together is 345 346```cmake 347set(configure_string "") 348config_option(EnableAwesome HAVE_AWESOME "Makes library awesome" DEFAULT ON) 349add_config_library(MyLibrary "${configure_string}") 350generate_autoconf(MyLibraryAutoconf "MyLibrary") 351target_link_libraries(MyLibrary PUBLIC MyLibrary_Config) 352target_link_libraries(LegacyApplication PRIVATE MyLibrary MyLibraryAutoconf) 353``` 354 355Stepping through line by line 356 357 * `set(configure_string "")` for simplicity the various `config_*` helpers automatically add to a variable called 358 `configure_string`, so we become by making sure this is blank 359 * `config_option(EnableAwesome HAVE_AWESOME "Makes library awesome" DEFAULT ON)` this declares a configuration 360 variable that will appear in CMake scripts and the cmake-gui as `EnableAwesome` and will appear in the generated 361 C header as `CONFIG_HAVE_AWESOME` 362 * `add_config_library(MyLibrary "${configure_string}")` generates a `MyLibrary_Config` target, which is an interface 363 library that has a generated C header based on the provided configuration string. It also adds `MyLibrary` to 364 a global list of configuration libraries. This global list can be used if you want to generate a library that 365 contains "all the configurations in the system" (which is what the original `autoconf.h` was) 366 * `generate_autoconf(MyLibraryAutoconf "MyLibrary")` generates a `MyLibraryAutoconf` target, which is an interface 367 library that depends upon `MyLibrary_Config` and will provide an `autoconf.h` file that includes the configuration 368 header from `MyLibrary_Config` 369 * `target_link_libraries(MyLibrary PUBLIC MyLibrary_Config)` allows `MyLibrary` to `#include` the generated 370 configuration header by doing `#include <MyLibrary/gen_config.h>` 371 * `target_link_libraries(LegacyApplication PRIVATE MyLibrary MyLibraryAutoconf)` allows `LegacyApplication` to 372 `#include <autoconf.h>` from `MyLibraryAutoconf`. The `autoconf.h` in this case will contain `#include <MyLibrary/gen_config.h>` 373 374For more details of the different `config_*` helpers read the comments on the functions in `kernel/tools/helpers.cmake` 375 376## Gotchas 377 378List of gotchas and easy mistakes that can be made when using cmake 379 380 * Configuration files passed to to cmake with `-C` *must* end in `.cmake`, otherwise CMake will silently throw 381 away your file 382