blob: ab9a59179aeec83e95c448d73a09b2834a8f5564 [file] [log] [blame] [view]
# Build your kernels and drivers with Bazel
[TOC]
**Note**:
You may view the documentation for the following Bazel rules and macros on
Android Continuous Integration. See
[API Reference and Documentation for all rules](api_reference.md).
## Setting up the workspace
* (Recommended) To use Kleaf tooling as a dependent Bazel module, see
[Setting up DDK workspace](ddk/workspace.md).
* To use Kleaf tooling as the root Bazel module, see
[Use @kleaf as root module (legacy)](bzlmod.md#use-kleaf-as-root-module-legacy).
* Building without Bzlmod is deprecated and will not be supported in
Android 16 and above.
## Building a custom kernel
**WARNING**: It is recommended to use the common Android kernel
under `//common` (the so-called "mixed build") instead of building a custom
kernel.
You may define a `kernel_build` target to build a custom kernel. The name of
the `kernel_build` target is usually the name of your device, e.g. `tuna`.
The `outs` attribute of the target should align with the `FILES` variable in
build.config. This may include DTB files and kernel images, e.g. `vmlinux`.
The `module_outs` attribute of the target includes the list of in-tree drivers
that you are building. See section to [build in-tree drivers (Step 1)](#step-1)
below.
```
load("//build/kernel/kleaf:kernel.bzl","kernel_build")
load("//build/kernel/kleaf:common_kernels.bzl", "arm64_outs")
kernel_build(
name = "tuna",
srcs = glob(
["**"],
exclude = [
"**/BUILD.bazel",
"**/*.bzl",
".git/**",
],
),
outs = arm64_outs,
build_config = "build.config.tuna",
)
```
## Building kernel modules and DTB files
### Step 0: (Optional) Create a skeleton `BUILD.bazel` file
This step automates most of the following steps for you.
First, install
[Buildozer](https://github.com/bazelbuild/buildtools/tree/master/buildozer).
Make sure that it is available in `$PATH`, or under `$GOPATH/bin`, or under
`$HOME/go/bin`. See the script below for details on how `buildozer` is searched
for.
Next, execute `build_config_to_bazel.py` script. Set `BUILD_CONFIG` accordingly
if you don't have a top level `build.config` file. Example:
```shell
$ BUILD_CONFIG=common-modules/virtual-device/build.config.virtual_device.x86_64 \
build/kernel/kleaf/build_config_to_bazel.py
```
Sample output:
```text
fixed /home/elsk/android/kernel/common-modules/virtual-device/BUILD.bazel
```
Then, examine the modified file(s), indicated in the command output.
There may be several `FIXME` comments that requires human intervention.
Go through the steps below to fix them accordingly.
**NOTE**: Human intervention is still required for the generated file.
**NOTE**: The script may modify multiple files. All of them should be examined.
**NOTE**: The file is generated based on a number of heuristics. Even if some
attributes aren't commented with `FIXME`, they may not be 100% correct. Go
through the steps below to fix the file to suit your needs.
### Step 1: (Optional) Define a target to build in-tree drivers and DTB files {#step-1}
If you have a separate kernel tree to build in-tree drivers, define
a `kernel_build` target to build these modules. The name of the `kernel_build`
target is usually the name of your device, e.g. `tuna`.
If you also have external kernel modules to be built, be sure to set visibility
accordingly, so that the targets to build external kernel modules can refer to
this `kernel_build` target.
If you are building a custom kernel, you may reuse the existing `kernel_build`
target, and keep kernel images in `outs`. If you are building against GKI, set
the `base_kernel` attribute accordingly (e.g. to `//common:kernel_aarch64`).
The `build_config` attribute of the target should point to the
main `build.config` file. To use `build.config` files generated on the fly, you
may use the `kernel_build_config` rule. See example for Pixel 2021 below.
The `outs` attribute of the target should align with the `FILES` variable in
build.config. This may include DTB files.
The `module_outs` attribute of the target includes the list of in-tree drivers
that you are building.
* Hint: You may leave the list empty and build the target. If the list is not
up to date, modify the list according to the error message.
**Note**: It is recommended that kernel modules are moved out of the kernel tree
to be built as external kernel modules. This means keeping the list
of `module_outs` empty or as short as possible. See Step 2 for building external
kernel modules.
For other build configurations defined in the `build.config` file, see
[build_configs.md](build_configs.md).
Example for Pixel 2021 (see the `kernel_build` target named `slider`):
[https://android.googlesource.com/kernel/google-modules/raviole-device/+/refs/heads/android13-gs-raviole-5.15/BUILD.bazel](https://android.googlesource.com/kernel/google-modules/raviole-device/+/refs/heads/android13-gs-raviole-5.15/BUILD.bazel)
### Step 2: Define targets to build external kernel modules
Define `kernel_module` targets to build external kernel modules. You should
create a `kernel_module` target for each item in `EXT_MODULES` variable
in `build.config`.
The `kernel_build` attribute should be the target to the `kernel_build` you have
previously created in step 1, or `//common:kernel_aarch64` if you did not do
step 1.
The `outs` attribute should be set to a list of `*.ko` files built by this
external module.
* Hint: You may leave the list empty and build the target. If the list is not
up to date, modify the list according to the error message.
Be sure to set visibility accordingly, so that these targets are visible to
the `kernel_modules_install` target that will be created in step 3.
If the module depends on other modules, set `kernel_module_deps` accordingly.
See the `bms` and `power/reset` module below for an example.
If the module depends on headers in other locations, add headers to a filegroup,
then add the headers to `srcs`. See the `bms` and `power/reset` module below for
an example.
Minimal example for the `edgetpu` driver of Pixel 2021:
[https://android.googlesource.com/kernel/google-modules/edgetpu/+/refs/heads/android-gs-raviole-mainline/drivers/edgetpu/BUILD.bazel](https://android.googlesource.com/kernel/google-modules/edgetpu/+/refs/heads/android-gs-raviole-mainline/drivers/edgetpu/BUILD.bazel)
Example for the `bms` driver of Pixel 2021:
[https://android.googlesource.com/kernel/google-modules/bms/+/refs/heads/android-gs-raviole-mainline/BUILD.bazel](https://android.googlesource.com/kernel/google-modules/bms/+/refs/heads/android-gs-raviole-mainline/BUILD.bazel)
Example for the `power/reset` driver of Pixel 2021:
[https://android.googlesource.com/kernel/google-modules/power/reset/+/refs/heads/android-gs-raviole-mainline/BUILD.bazel](https://android.googlesource.com/kernel/google-modules/power/reset/+/refs/heads/android-gs-raviole-mainline/BUILD.bazel)
### Step 3: Define a target to run `depmod`
Define a `kernel_modules_install` target that includes all external kernel
modules created in Step 2. This is equivalent to running `make modules_install`,
which runs `depmod`.
The name of the target is usually the name of your device
with `_modules_install` appended to it, e.g. `tuna_modules_install`.
See Step 2 to determine the `kernel_build` attribute of the target.
Example for Pixel 2021 (see the `kernel_modules_install` target
named `slider_modules_install`):
[https://android.googlesource.com/kernel/google-modules/raviole-device/+/refs/heads/android13-gs-raviole-5.15/BUILD.bazel](https://android.googlesource.com/kernel/google-modules/raviole-device/+/refs/heads/android13-gs-raviole-5.15/BUILD.bazel)
### Step 4: (Optional) Define a target to build all boot images
The `kernel_images` macro produces partition images that are ready to be flashed
and tested immediately on your device. It can build the `initramfs`
image, `boot` image, `vendor_boot` image, `vendor_dlkm` image, `system_dlkm` image, etc.
The name of the target is usually the name of your device with `_images`
appended to it, e.g. `tuna_images`.
If you do not need to build any partition images, skip this step.
Example for Pixel 2021 (see the `kernel_images` target named `slider_images`):
[https://android.googlesource.com/kernel/google-modules/raviole-device/+/refs/heads/android13-gs-raviole-5.15/BUILD.bazel](https://android.googlesource.com/kernel/google-modules/raviole-device/+/refs/heads/android13-gs-raviole-5.15/BUILD.bazel)
### Step 5: Define targets for distribution {#step-5}
Define a `pkg_files` target and a `pkg_install` target that includes the targets
you want in the distribution directory. The name of this `pkg_install` target
is usually the name of your device with `_dist` appended to it, e.g.
`tuna_dist`.
You may set `strip_prefix = strip_prefix.files_only()` so the directory
structure within `destdir` is flattened. If an alternative directory structure
is desired, use other rules and functions in `@rules_pkg//pkg:mappings.bzl`
to achieve this.
It is recommended to set `destdir` so you do not have to specify it in the
command line every time.
Add the following to the `srcs` attribute of the `pkg_files` target:
* The name of the `kernel_build` you have created in Step 1,
e.g. `:tuna`. This adds all `outs`
and `module_outs` to the distribution directory.
* This usually includes DTB files and in-tree kernel modules.
* The name of the `kernel_modules_install` target you have created in Step 3.
You may skip the `kernel_modules` targets created in Step 2, because
the `kernel_modules_install` target includes all `kernel_modules` targets.
This copies all external kernel modules to the distribution directory.
* The name of the `kernel_images` target you have created in Step 4. This copies
all partition images to the distribution directory.
* GKI artifacts, including:
* `//common:kernel_aarch64`
* `//common:kernel_aarch64_additional_artifacts`
* UAPI headers, e.g. `//common:kernel_aarch64_uapi_headers`
* GKI modules
* If you are using all GKI modules, add `//common:kernel_aarch64_modules`.
* If you are using part of the GKI modules, add them individually, e.g.:
* `//common:kernel_aarch64/zram.ko`
* `//common:kernel_aarch64/zsmalloc.ko`
* Modules from the device kernel build with the same name as GKI modules
(e.g. on android13-5.15, you have `zram.ko` in `kernel_build.module_outs`)
does not need to be specified, because `module_outs` are added to
distribution.
Then, add the `pkg_files` target to the `srcs` attribute of the `pkg_install`
target.
Example:
```
load("@rules_pkg//pkg:install.bzl", "pkg_install")
load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix")
pkg_files(
name = "tuna_files",
srcs = [
":tuna",
":tuna_images",
":tuna_modules_install",
"//common:kernel_aarch64_uapi_headers",
"//common:kernel_aarch64",
"//common:kernel_aarch64_modules",
"//common:kernel_aarch64_additional_artifacts",
],
strip_prefix = strip_prefix.files_only(),
visibility = ["//visibility:private"],
)
pkg_install(
name = "tuna_dist",
srcs = [":tuna_files"],
destdir = "out/tuna/dist",
visibility = ["//visibility:private"],
)
```
See [rules_pkg](https://github.com/bazelbuild/rules_pkg) for details on how to
use `pkg_files`, `strip_prefix`, and `pkg_install` properly.
### Step 6: Build, flash and test
```shell
# Optional: prepare the device by flashing a base build.
# During development, you may want to wipe, disable verity and disable verification.
# fastboot update tuna-img.zip -w --disable-verity --disable-verification
# Assuming dist_dir=out/dist
$ tools/bazel run //private/path/to/sources:tuna_dist
# Flash static partitions
$ fastboot flash boot out/dist/boot.img
$ fastboot flash system_dlkm out/dist/system_dlkm.img
$ fastboot flash vendor_boot out/dist/vendor_boot.img
$ fastboot flash dtbo out/dist/dtbo.img
$ fastboot reboot fastboot
# Flash dynamic partitions
$ fastboot flash vendor_dlkm out/dist/vendor_dlkm.img
$ fastboot reboot
```
## Resolving common errors
See [errors.md](errors.md).
## Handling SCM version
See [scmversion.md](scmversion.md).
## Advanced usage
### Disable LTO during development
See [lto.md](lto.md).
### Using configurable build attributes `select()`
See official Bazel documentation for `select()`
here: https://docs.bazel.build/versions/main/configurable-attributes.html
In general, inputs to a target are configurable, while declared outputs are not.
One exception is that the `kernel_build` rule provides limited support
of `select()` in `outs` and `module_outs` attributes. See
[documentations](api_reference.md) of `kernel_build` for details.
### .bazelrc files
By default, the `.bazelrc` (symlink to `build/kernel/kleaf/common.bazelrc`)
tries to import the following two files if they exist:
* `device.bazelrc`: Device-specific bazelrc file (e.g. GKI prebuilt settings)
* `user.bazelrc`: User-specific bazelrc file (e.g. LTO settings)
To add device-specific configurations, you may create a `device.bazelrc`
file in the device kernel tree, then create a symlink at the repo root.
### Notes on hermeticity
Bazel builds are hermetic by default. Hermeticity is ensured by manually
declaring each target to depend on `//build/kernel:hermetic-tools`.
At this time of writing (2025-01-03), the following binaries are still
expected from the environement, or host machine, to build the kernel with
Bazel, in addition to the list of the allowlist of host tools specified in
`//build/kernel:hermetic-tools`. This is because the following usage does
not depend on `//build/kernel:hermetic-tools`.
* `echo`, `readlink`, `git` used by `build/kernel/kleaf/workspace_status.sh`
If you use the following rules, there are known issues of non-hermeticity:
* [`copy_file`](https://github.com/bazelbuild/bazel-skylib/blob/main/rules/copy_file.bzl)
uses `cp` from the host machine