How to manually build android kernel without standard bazel/build.sh explained.

Introduction

As explained on Build kernels, Android kernel build is straight forward by using bazel/build.sh. However, it's little bit cumbersome for those who are trying to build android kernel by regarding it as just one variation of linux kernel. This is because android kernel consists of kernel source tree and many other surrounding scripts. The purpose of these surrounding scripts to assure GKI concept, in one view. Due to this situation, it's hard to easily modify certain Kconfig configuration by hand. There is no "menuconfig" and other standard operation for linux kernel may not applied directly.

Preparation

To let build reproducible, I use docker image created by following Dockerfile.

FROM ubuntu:24.04

RUN apt update && apt install -y \
    make \
    clang \
    lld \
    llvm \
    git \
    bc \
    flex \
    bison \
    gawk \
    lz4 \
    cpio \
    xz-utils \
    libssl-dev \
    libelf-dev \
    libdw-dev \
    libc6-dev-amd64-cross \
    ncurses-dev \
    pahole

Most of packages are usually needed for linux kernel build but I tuned little bit for android kernel. The most significant point is to use clang, instead of using gcc. After saving above content as Dockerfile and run:

docker build -t android-kernel-build .

When we use build.sh, clang prebuilt binary is repo synced to local workspace and it is used for compilation. While this way can also achieve reproducible build, it takes much time to fetch all prebuilt toolchan at the beginning of procedure. docker build corresponds to it here, but it's faster than repo sync.

Build kernel

This page procedure is verified by following revision of android common kernel. Reader can use your own revision of android kernel source tree.

git clone -b android13-5.15-2025-03_r5 https://android.googlesource.com/kernel/common

Following commands are the most straight forward to build bzImage for x86 archirecture.

cd common
docker run -it --rm -v $(pwd):$(pwd) -w $(pwd) android-kernel-build make LLVM=1 O=build-android gki_defconfig
docker run -it --rm -v $(pwd):$(pwd) -w $(pwd) android-kernel-build make LLVM=1 O=build-android bzImage

Finally you will see bzImage at build-android/arch/x86/boot/bzImage.

  ZOFFSET arch/x86/boot/zoffset.h
  OBJCOPY arch/x86/boot/vmlinux.bin
  AS      arch/x86/boot/header.o
  LD      arch/x86/boot/setup.elf
  OBJCOPY arch/x86/boot/setup.bin
  BUILD   arch/x86/boot/bzImage
Kernel: arch/x86/boot/bzImage is ready  (#1)
make[1]: Leaving directory '/mnt/ssd/common/build-android'

This image is used to run on, for instance, by QEMU.

Build modules

At first, it's strange to say but I don't recommend to build modules during development. If =y from menuconfig solve your situation, development, I recommend to use =y built-in function on top of GKI. On real Android operation system, it's encouraged to split kernel function strictly into GKI part and vendor module part. But during development you don't have to follow that requirement. Off course it depends on your purpose but I assume =y is more suitable to the reader of this page.

In kernel module

You can use menuconfig and choose =m. Your target configuration is clear, this is best way.

docker run -it --rm -v $(pwd):$(pwd) -w $(pwd) android-kernel-build /bin/bash
make LLVM=1 O=build-android menuconfig
make LLVM=1 O=build-android modules

Out-of-tree kernel module

As example, I will use virtual-device from AOSP. Make sure $LINUX contains path to common linux source tree.

git clone --depth 1 -b trout-android14-6.1 https://android.googlesource.com/kernel/common-modules/virtual-device
docker run -it --rm -v $LINUX:$LINUX -v $(pwd):$(pwd) -w $(pwd) -u $(id -u) android-kernel-build /bin/bash

Following comands are in contiainer.

cd virtual-device
echo "ccflags-y += -I$(pwd)/include/uapi" >> virtio_video/Kbuild
make -C $LINUX LLVM=1 O=build-android M=$(pwd) MO=$(pwd) modules

Unfortunaly, revison trout-android14-6.1 cannot compile agains the above common revision: android13-5.15-2025-03_r5. I need to check compatibility with other revision or modify module source code.

Next step

Run generated bzImage and *.ko on emulator or the board.