150 lines
7.4 KiB
Markdown
150 lines
7.4 KiB
Markdown
# 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
|
|
`<vendor>_<arch>_<variant>` 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/<target_name>.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:
|
|
|
|
* `<build_target>/libchre.so` and `libchre.a`: the resulting CHRE framework
|
|
binary, built as a dynamic/static library
|
|
|
|
* `<build_target>_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)
|