| Brian Duddie | 7f23a87 | 2020-07-01 14:27:31 -0700 | [diff] [blame] | 1 | # CHRE Framework Build System |
| 2 | |
| 3 | [TOC] |
| 4 | |
| 5 | The CHRE build system is based on Make, and uses a set of Makefiles that allow |
| 6 | building the CHRE framework for a variety of hardware and software architectures |
| 7 | and variants (e.g. different combinations of CPU and OS/underlying system). It |
| 8 | is also flexible to different build toolchains (though LLVM/Clang or GCC are |
| 9 | recommended), by abstracting out key operations to a few Make or environment |
| 10 | variables. While the CHRE framework source code may be integrated into another |
| 11 | build system, it can be beneficial to leverage the existing build system to |
| 12 | reduce maintenance burden when the CHRE framework is updated. Additionally, it |
| 13 | should be possible to build nanoapps from the CHRE build system (to have |
| 14 | commonality across devices), and the CHRE framework build shares configuration |
| 15 | with the nanoapp build. |
| 16 | |
| 17 | By default, the output of the build is linked into both a static archive |
| 18 | `libchre.a` and a shared library `libchre.so`, though generally only one of the |
| 19 | two is used, depending on the target device details. |
| 20 | |
| 21 | ## Design |
| 22 | |
| 23 | The CHRE build system was originally designed around the philosophy that a |
| 24 | vanilla invocation of `make` or `make all` should build any given nanoapp for |
| 25 | all targets. This allows for efficient use of the job scheduler in the Make |
| 26 | build system for multi-threaded builds and also promotes a level of separation |
| 27 | of concerns between targets (this is not enforced by any Make language |
| 28 | construct, merely convention). In practice, the CHRE build system is rarely used |
| 29 | to build multiple targets with one invocation of Make. However, the design goal |
| 30 | is carried forward for the variant support and separation of concerns between |
| 31 | targets. |
| 32 | |
| 33 | All variant-specific compiler and linker flags are held under variables that |
| 34 | only apply to their specific target. This encourages developers to avoid leaking |
| 35 | build details between targets. This is important because not all compiler or |
| 36 | linker flags are compatible with all toolchains. For example: if a target uses a |
| 37 | compiler that does not support `-Wdouble-promotion`, but this were to be |
| 38 | enforced for all builds, then by definition this target would not compatible |
| 39 | with the CHRE build. The goal is for the CHRE build to be as flexible as |
| 40 | possible. |
| 41 | |
| 42 | ### Build Template |
| 43 | |
| 44 | The CHRE build system is implemented using template meta-programming techniques. |
| 45 | A build template is used to create Make rules for tasks that are common to all |
| 46 | targets. This includes compiling C/C++/assembly sources, linking, nanoapp header |
| 47 | generation, etc. The rationale behind this approach is to reduce boilerplate |
| 48 | when adding support for a new build target. |
| 49 | |
| 50 | The build template is located at `build/build_template.mk`, and is documented |
| 51 | with all the variables used to generate build targets, like `TARGET_CFLAGS`. |
| 52 | |
| 53 | ## Build Targets (Variants) |
| 54 | |
| 55 | Compiling the framework for different devices is done by specifying the build |
| 56 | target when invoking `make`. Conventionally, build targets consist of three |
| 57 | parts: (software) vendor, architecture and variant and follow the |
| 58 | `<vendor>_<arch>_<variant>` pattern. A “vendor” is typically the company that |
| 59 | created the CHRE implementation, which may bring with it some details related to |
| 60 | nanoapp compatibility, for example the Nanoapp Support Library from the same |
| 61 | vendor may be required. The “arch” field refers to the Instruction Set |
| 62 | Architecture (ISA) and related compiler configuration to create a binary for the |
| 63 | target processor. The “variant” is primarily related to the underlying platform |
| 64 | software that the CHRE framework builds on top of, such as the combination of |
| 65 | operating system and other software needed to select the appropriate combination |
| 66 | of code in the `platform/` folder, but can also define other attributes of the |
| 67 | build, such as the target memory region for the binary. If a vendor, |
| 68 | architecture, or variant consist of multiple words or components, then they |
| 69 | should be separated by a hyphen and not an underscore. |
| 70 | |
| 71 | For example, if we assume that a fictional company named Aperture developed its |
| 72 | own CHRE framework implementation, targeting a CPU family called Potato, and a |
| 73 | collection of platform software called GladOS/Cake, then a suitable build target |
| 74 | name would be `aperture_potato_glados-cake`. |
| 75 | |
| 76 | The build target may optionally have `_debug` appended, which is a common suffix |
| 77 | which enables `-g` and any additional target-specific debug flags. |
| 78 | |
| 79 | ### Creating a New Build Target |
| 80 | |
| 81 | #### Architecture Support |
| 82 | |
| 83 | The architecture-specific portion of the build deals with mainly the build |
| 84 | toolchain, and its associated flags. |
| 85 | |
| 86 | It is easiest to check if the architecture is currently listed in `build/arch`, |
| 87 | and if it is, _Hooray! You're (almost) done_. It is still worthwhile to quickly |
| 88 | read through to know how the build is layered. |
| 89 | |
| 90 | CHRE expects the build toolchain to be exported via Makefile variables, |
| 91 | specifically the compiler (`TARGET_CC`), archiver (`TARGET_AR`), and the linker |
| 92 | (`TARGET_LD`). Architecture specific compiler and linker flags are passed in via |
| 93 | the `TARGET_CFLAGS` and `TARGET_LDFLAGS` respectively. Additional |
| 94 | architecture-specific configuration is possible - refer to existing files under |
| 95 | `build/arch` and `build/build_template.mk` for details. |
| 96 | |
| 97 | #### Build Target Makefile |
| 98 | |
| 99 | Makefiles for each build target can be found at |
| 100 | `build/variant/<target_name>.mk`. These files are included at the end of the |
| 101 | top-level Makefile, and has the responsibility of collecting arguments for the |
| 102 | build template and invoking it to instantiate build rules. This involves doing |
| 103 | steps including (not an exhaustive listing): |
| 104 | |
| 105 | * Setting the target name and platform ID |
| 106 | |
| 107 | * Configuring (if needed) and including the apporpriate `build/arch/*.mk` file |
| 108 | |
| 109 | * Collecting sources and flags specific to the platform into |
| 110 | `TARGET_VARIANT_SRCS` and `TARGET_CFLAGS` |
| 111 | |
| 112 | * Including `build/build_template.mk` to instantiate the build targets - this |
| 113 | must be the last step, as the make targets cannot be modified once generated |
| 114 | |
| 115 | Refer to existing files under `build/variant` for examples. |
| 116 | |
| 117 | ## Device Variants |
| 118 | |
| 119 | While the build target is primarily concerned with configuring the CHRE build |
| 120 | for a particular chipset, the same chipset can appear in multiple device |
| 121 | models/SKUs, potentially with different peripheral hardware, targeted levels of |
| 122 | feature support, etc. Additionally, a device/chip vendor may wish to provide |
| 123 | additional build customization outside of the Makefiles contained in the |
| 124 | system/chre project. The build system supports configuration at this level via |
| 125 | the device variant makefile, typically named `variant.mk`, which is injected |
| 126 | into the build by setting the `CHRE_VARIANT_MK_INCLUDES` environment variable |
| 127 | when invoking the top-level Makefile. Refer to the file |
| 128 | `variant/android/variant.mk` for an example. |
| 129 | |
| 130 | ## Platform Sources |
| 131 | |
| 132 | The file at `platform/platform.mk` lists sources and flags needed to compile the |
| 133 | CHRE framework for each supported platform. These must be added to Make |
| 134 | variables prefixed with the platform name (for example, `SIM_SRCS` for platform |
| 135 | sources used with the simulator build target), and not `COMMON_SRCS` or other |
| 136 | common variables, to avoid affecting other build targets. |
| 137 | |
| 138 | ## Build Artifacts |
| 139 | |
| 140 | At the end of a successful build, the following are generated in the `out` |
| 141 | directory: |
| 142 | |
| 143 | * `<build_target>/libchre.so` and `libchre.a`: the resulting CHRE framework |
| 144 | binary, built as a dynamic/static library |
| 145 | |
| 146 | * `<build_target>_objs/`: Directory with object files and other intermediates |
| 147 | |
| 148 | * Depending on the build target, additional intermediates (e.g. `nanopb_gen` for |
| 149 | files generated for use with NanoPB) |