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.
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) 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", )
BUILD.bazel
fileThis step automates most of the following steps for you.
First, install 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:
$ BUILD_CONFIG=common-modules/virtual-device/build.config.virtual_device.x86_64 \ build/kernel/kleaf/build_config_to_bazel.py
Sample output:
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.
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.
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.
Example for Pixel 2021 (see the kernel_build
target named slider
):
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.
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:
Example for the bms
driver of Pixel 2021:
Example for the power/reset
driver of Pixel 2021:
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
):
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
):
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:
kernel_build
you have created in Step 1, e.g. :tuna
. This adds all outs
and module_outs
to the distribution directory.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.kernel_images
target you have created in Step 4. This copies all partition images to the distribution directory.//common:kernel_aarch64
//common:kernel_aarch64_additional_artifacts
//common:kernel_aarch64_uapi_headers
//common:kernel_aarch64_modules
.//common:kernel_aarch64/zram.ko
//common:kernel_aarch64/zsmalloc.ko
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 for details on how to use pkg_files
, strip_prefix
, and pkg_install
properly.
# 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
See errors.md.
See scmversion.md.
See lto.md.
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 of kernel_build
for details.
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.
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
uses cp
from the host machine