blob: f946b2e09a2718a625b87a1f2022029cce317164 [file] [log] [blame]
Balint Dobszay637f4732019-11-13 12:48:00 +01001TF-A CMake buildsystem
2======================
3
4:Author: Balint Dobszay
5:Organization: Arm Limited
6:Contact: Balint Dobszay <balint.dobszay@arm.com>
7:Status: Accepted
8
9.. contents:: Table of Contents
10
11Abstract
12--------
13This document presents a proposal for a new buildsystem for TF-A using CMake,
Olivier Deprezaac64b02024-03-20 09:41:29 +010014and as part of this a reusable CMake framework for embedded projects.
Balint Dobszay637f4732019-11-13 12:48:00 +010015
16Introduction
17------------
18The current Makefile based buildsystem of TF-A has become complicated and hard
19to maintain, there is a need for a new, more flexible solution. The proposal is
20to use CMake language for the new buildsystem. The main reasons of this decision
21are the following:
22
23* It is a well-established, mature tool, widely accepted by open-source
24 projects.
25* TF-M is already using CMake, reducing fragmentation for tf.org projects can be
26 beneficial.
27* CMake has various advantages over Make, e.g.:
28
29 * Host and target system agnostic project.
30 * CMake project is scalable, supports project modularization.
31 * Supports software integration.
32 * Out-of-the-box support for integration with several tools (e.g. project
33 generation for various IDEs, integration with cppcheck, etc).
34
35Of course there are drawbacks too:
36
37* Language is problematic (e.g. variable scope).
38* Not embedded approach.
39
40To overcome these and other problems, we need to create workarounds for some
41tasks, wrap CMake functions, etc. Since this functionality can be useful in
42other embedded projects too, it is beneficial to collect the new code into a
43reusable framework and store this in a separate repository. The following
44diagram provides an overview of the framework structure:
45
46|Framework structure|
47
48Main features
49-------------
50
51Structured configuration description
52^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
53In the current Makefile system the build configuration description, validation,
54processing, and the target creation, source file description are mixed and
55spread across several files. One of the goals of the framework is to organize
56this.
57
58The framework provides a solution to describe the input build parameters, flags,
59macros, etc. in a structured way. It contains two utilities for this purpose:
60
61* Map: simple key-value pair implementation.
62* Group: collection of related maps.
63
64The related parameters shall be packed into a group (or "setting group"). The
65setting groups shall be defined and filled with content in config files.
66Currently the config files are created and edited manually, but later a
67configuration management tool (e.g. Kconfig) shall be used to generate these
68files. Therefore, the framework does not contain parameter validation and
69conflict checking, these shall be handled by the configuration tool.
70
71Target description
72^^^^^^^^^^^^^^^^^^
73The framework provides an API called STGT ('simple target') to describe the
74targets, i.e. what is the build output, what source files are used, what
75libraries are linked, etc. The API wraps the CMake target functions, and also
76extends the built-in functionality, it can use the setting groups described in
77the previous section. A group can be applied onto a target, i.e. a collection of
78macros, flags, etc. can be applied onto the given output executable/library.
79This provides a more granular way than the current Makefile system where most of
80these are global and applied onto each target.
81
82Compiler abstraction
83^^^^^^^^^^^^^^^^^^^^
84Apart from the built-in CMake usage of the compiler, there are some common tasks
85that CMake does not solve (e.g. preprocessing a file). For these tasks the
86framework uses wrapper functions instead of direct calls to the compiler. This
87way it is not tied to one specific compiler.
88
89External tools
90^^^^^^^^^^^^^^
91In the TF-A buildsystem some external tools are used, e.g. fiptool for image
92generation or dtc for device tree compilation. These tools have to be found
93and/or built by the framework. For this, the CMake find_package functionality is
94used, any other necessary tools can be added later.
95
96Workflow
97--------
98The following diagram demonstrates the development workflow using the framework:
99
100|Framework workflow|
101
102The process can be split into two main phases:
103
104In the provisioning phase, first we have to obtain the necessary resources, i.e.
105clone the code repository and other dependencies. Next we have to do the
106configuration, preferably using a config tool like KConfig.
107
108In the development phase first we run CMake, which will generate the buildsystem
109using the selected generator backend (currently only the Makefile generator is
110supported). After this we run the selected build tool which in turn calls the
111compiler, linker, packaging tool, etc. Finally we can run and debug the output
112executables.
113
114Usually during development only the steps in this second phase have to be
115repeated, while the provisioning phase needs to be done only once (or rarely).
116
117Example
118-------
119This is a short example for the basic framework usage.
120
121First, we create a setting group called *mem_conf* and fill it with several
122parameters. It is worth noting the difference between *CONFIG* and *DEFINE*
123types: the former is only a CMake domain option, the latter is only a C language
124macro.
125
126Next, we create a target called *fw1* and add the *mem_conf* setting group to
127it. This means that all source and header files used by the target will have all
128the parameters declared in the setting group. Then we set the target type to
129executable, and add some source files. Since the target has the parameters from
130the settings group, we can use it for conditionally adding source files. E.g.
131*dram_controller.c* will only be added if MEM_TYPE equals dram.
132
133.. code-block:: cmake
134
135 group_new(NAME mem_conf)
136 group_add(NAME mem_conf TYPE DEFINE KEY MEM_SIZE VAL 1024)
137 group_add(NAME mem_conf TYPE CONFIG DEFINE KEY MEM_TYPE VAL dram)
138 group_add(NAME mem_conf TYPE CFLAG KEY -Os)
139
140 stgt_create(NAME fw1)
141 stgt_add_setting(NAME fw1 GROUPS mem_conf)
142 stgt_set_target(NAME fw1 TYPE exe)
143
144 stgt_add_src(NAME fw1 SRC
145 ${CMAKE_SOURCE_DIR}/main.c
146 )
147
148 stgt_add_src_cond(NAME fw1 KEY MEM_TYPE VAL dram SRC
149 ${CMAKE_SOURCE_DIR}/dram_controller.c
150 )
151
152.. |Framework structure| image::
153 ../resources/diagrams/cmake_framework_structure.png
154 :width: 75 %
155
156.. |Framework workflow| image::
157 ../resources/diagrams/cmake_framework_workflow.png
158
159--------------
160
Olivier Deprezaac64b02024-03-20 09:41:29 +0100161*Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.*