1TF-A CMake buildsystem 2====================== 3 4:Author: Balint Dobszay 5:Organization: Arm Limited 6:Contact: Balint Dobszay <[email protected]> 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, 14and as part of this a reusable CMake framework for embedded projects. 15 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 161*Copyright (c) 2019-2024, Arm Limited and Contributors. All rights reserved.* 162