NameDateSize

..22-Jun-202015

all.cmakeH A D09-Mar-2020456

base.cmakeH A D09-Mar-20202.3 KiB

common.cmakeH A D09-Mar-2020759

default-CMakeLists.txtH A D09-Mar-2020938

griddleH A D13-May-202020.6 KiB

helpers/H12-Nov-202027

init-build.shH A D09-Mar-20201.8 KiB

LICENSE_BSD2.txtH A D25-Jul-20191.4 KiB

polly_toolchains/H09-Mar-20204

projects.cmakeH A D09-Mar-2020648

README.mdH A D09-Mar-202017.6 KiB

rust_targets/H22-Nov-20195

simulate_scripts/H09-Mar-20204

README.md

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