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