# CHRE Framework Build System

[TOC]

The CHRE build system is based on Make, and uses a set of Makefiles that allow
building the CHRE framework for a variety of hardware and software architectures
and variants (e.g. different combinations of CPU and OS/underlying system). It
is also flexible to different build toolchains (though LLVM/Clang or GCC are
recommended), by abstracting out key operations to a few Make or environment
variables. While the CHRE framework source code may be integrated into another
build system, it can be beneficial to leverage the existing build system to
reduce maintenance burden when the CHRE framework is updated. Additionally, it
should be possible to build nanoapps from the CHRE build system (to have
commonality across devices), and the CHRE framework build shares configuration
with the nanoapp build.

By default, the output of the build is linked into both a static archive
`libchre.a` and a shared library `libchre.so`, though generally only one of the
two is used, depending on the target device details.

## Design

The CHRE build system was originally designed around the philosophy that a
vanilla invocation of `make` or `make all` should build any given nanoapp for
all targets. This allows for efficient use of the job scheduler in the Make
build system for multi-threaded builds and also promotes a level of separation
of concerns between targets (this is not enforced by any Make language
construct, merely convention). In practice, the CHRE build system is rarely used
to build multiple targets with one invocation of Make. However, the design goal
is carried forward for the variant support and separation of concerns between
targets.

All variant-specific compiler and linker flags are held under variables that
only apply to their specific target. This encourages developers to avoid leaking
build details between targets. This is important because not all compiler or
linker flags are compatible with all toolchains. For example: if a target uses a
compiler that does not support `-Wdouble-promotion`, but this were to be
enforced for all builds, then by definition this target would not compatible
with the CHRE build. The goal is for the CHRE build to be as flexible as
possible.

### Build Template

The CHRE build system is implemented using template meta-programming techniques.
A build template is used to create Make rules for tasks that are common to all
targets. This includes compiling C/C++/assembly sources, linking, nanoapp header
generation, etc. The rationale behind this approach is to reduce boilerplate
when adding support for a new build target.

The build template is located at `build/build_template.mk`, and is documented
with all the variables used to generate build targets, like `TARGET_CFLAGS`.

## Build Targets (Variants)

Compiling the framework for different devices is done by specifying the build
target when invoking `make`. Conventionally, build targets consist of three
parts: (software) vendor, architecture and variant and follow the
`__` pattern. A “vendor” is typically the company that
created the CHRE implementation, which may bring with it some details related to
nanoapp compatibility, for example the Nanoapp Support Library from the same
vendor may be required. The “arch” field refers to the Instruction Set
Architecture (ISA) and related compiler configuration to create a binary for the
target processor. The “variant” is primarily related to the underlying platform
software that the CHRE framework builds on top of, such as the combination of
operating system and other software needed to select the appropriate combination
of code in the `platform/` folder, but can also define other attributes of the
build, such as the target memory region for the binary. If a vendor,
architecture, or variant consist of multiple words or components, then they
should be separated by a hyphen and not an underscore.

For example, if we assume that a fictional company named Aperture developed its
own CHRE framework implementation, targeting a CPU family called Potato, and a
collection of platform software called GladOS/Cake, then a suitable build target
name would be `aperture_potato_glados-cake`.

The build target may optionally have `_debug` appended, which is a common suffix
which enables `-g` and any additional target-specific debug flags.

### Creating a New Build Target

#### Architecture Support

The architecture-specific portion of the build deals with mainly the build
toolchain, and its associated flags.

It is easiest to check if the architecture is currently listed in `build/arch`,
and if it is, _Hooray! You're (almost) done_. It is still worthwhile to quickly
read through to know how the build is layered.

CHRE expects the build toolchain to be exported via Makefile variables,
specifically the compiler (`TARGET_CC`), archiver (`TARGET_AR`), and the linker
(`TARGET_LD`). Architecture specific compiler and linker flags are passed in via
the `TARGET_CFLAGS` and `TARGET_LDFLAGS` respectively. Additional
architecture-specific configuration is possible - refer to existing files under
`build/arch` and `build/build_template.mk` for details.

#### Build Target Makefile

Makefiles for each build target can be found at
`build/variant/.mk`. These files are included at the end of the
top-level Makefile, and has the responsibility of collecting arguments for the
build template and invoking it to instantiate build rules. This involves doing
steps including (not an exhaustive listing):

* Setting the target name and platform ID

* Configuring (if needed) and including the apporpriate `build/arch/*.mk` file

* Collecting sources and flags specific to the platform into
  `TARGET_VARIANT_SRCS` and `TARGET_CFLAGS`

* Including `build/build_template.mk` to instantiate the build targets - this
  must be the last step, as the make targets cannot be modified once generated

Refer to existing files under `build/variant` for examples.

## Device Variants

While the build target is primarily concerned with configuring the CHRE build
for a particular chipset, the same chipset can appear in multiple device
models/SKUs, potentially with different peripheral hardware, targeted levels of
feature support, etc. Additionally, a device/chip vendor may wish to provide
additional build customization outside of the Makefiles contained in the
system/chre project. The build system supports configuration at this level via
the device variant makefile, typically named `variant.mk`, which is injected
into the build by setting the `CHRE_VARIANT_MK_INCLUDES` environment variable
when invoking the top-level Makefile. Refer to the file
`variant/android/variant.mk` for an example.

## Platform Sources

The file at `platform/platform.mk` lists sources and flags needed to compile the
CHRE framework for each supported platform. These must be added to Make
variables prefixed with the platform name (for example, `SIM_SRCS` for platform
sources used with the simulator build target), and not `COMMON_SRCS` or other
common variables, to avoid affecting other build targets.

## Build Artifacts

At the end of a successful build, the following are generated in the `out`
directory:

* `/libchre.so` and `libchre.a`: the resulting CHRE framework
  binary, built as a dynamic/static library

* `_objs/`: Directory with object files and other intermediates

* Depending on the build target, additional intermediates (e.g. `nanopb_gen` for
  files generated for use with NanoPB)