There might be times in which you’d want to build the LineageOS kernel for a device without syncing the whole repo and establishing a build environment. Maybe you want to prebuilt a stable kernel for a recovery or maybe you just want to make a custom kernel targetting Lineage.
As of the time of writing the android kernel is built using Clang and parts of GCC. This might change in the future. I might write up a new article or update this one if that happens. Or maybe not…
Since the GCC toolchain for android is getting deprecated by Google you’ll need to get the specific one used for Lineage for your device.
First thing you’ll do is look at the branch in your kernel repository. That will indicate which toolchains you’ll need to use. Note that down for now.
Then you’ll go to the LineageOS/android
repository. That contains the repo manifests used for establishing a build environment. There is a lot in there but we don’t care about most of it.
At the time of writing the build system is still provided by Google, but this might change in the future. What this means ultimately is which manifest you should look for. If Google it would be in default.xml
if Lineage it will be in snippets/lineage.xml
.
In there you’ll look for prebuilts/
and locate the relevant toolchains.
Currently as follows:
prebuilts/clang/host/linux-x86
prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9
prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9
prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9
Clone these repositories from aosp: https://android.googlesource.com
After you’ve done that look at the refs/tags
in the manifest for the appropriate remote. Checkout all the cloned repositories to that branch/tag to get them to the appropriate versions.
SUCCESS! You’re now ready to build the kernel.
Just clone the appropriate android_kernel_
repository and cd
in to it. Checkout the branch to whatever version you want to build.
Just in case the repo is dirty run a clean first.
make clean && make mrproper
Make the output directory
mkdir out
Create the .config from the appropriate defconfig found in /arch/<device arch>/configs
Specify ARCH
, SUBARCH
and your Output directory
make O=out ARCH=arm64 SUBARCH=arm mydevice_defconfig
Build the kernel.
Usually you’d export these variables, but I’ve heard that it might cause issues, so just pass them inline.
O
- The output path
ARCH
- Device architecture arm
arm64
x86
etc (look in /arch
)
SUBARCH
- same as above
CC
- Android uses clang
now
NM
- The name mangling binary. Google prefers the one from LLVM. llvm-nm
OBJCOPY
- The objcopy binary. Google prefers the one from LLVM. llvm-objcopy
LD
- The linker binary. Usually not setting this is fine, but some kernels will fail compiling wth the default one, usually ld.gold
. Try different linkers here if it fails. From experience the LLVM linker ld.lld
works well.
PATH
- Append the path to the clang bin
directory and the gcc bin
directories. Some kernels might need more than one gcc. For example both aarch64
and arm
LD_LIBRARY_PATH
- Append the path to the clang libraries directory. lib
or lib64
(Might also be needed for gcc libs)
DEFCONFIG
- The device defconfig name like in the previous step.
CROSS_COMPILE
- The Android cross compiler prefix for the arch (from gcc). For example aarch64-linux-android-
or arm-linux-androideabi-
or aarch64-linux-gnu-
or arm-linux-gnueabi-
CROSS_COMPILE_ARM32
- Sometimes needed in some kernels for vDSO. Set it to the appropriate gcc prefix. arm-linux-androideabi-
CLANG_TRIPLE
- Clang will normally get it’s --target
from CROSS_COMPILE
which will break stack protector. Set this to the appropriate gnu target. For example aarch64-linux-gnu-
or arm-linux-gnueabi-
PATH make -j$(nproc) O ARCH SUBARCH CC NM OBJCOPY LD LD_LIBRARY_PATH DEFCONFIG CLANG_TRIPLE CROSS_COMPILE CROSS_COMPILE_ARM32
Some devices use Device Tree Overlays. These have various descriptions of hardware similar to ACPI on BIOS. Before the kernels were specifically tailored to every device but with this feature many embedded devices can use the same kernel.
What this means for us is that we might want to ship custom DTB and DTBO images, and to do so we must build them.
git clone https://android.googlesource.com/platform/system/tools/mkbootimg
git clone https://android.googlesource.com/platform/system/libufdt
If you haven’t already, you’ll need to build the kernel, like described above. Go do that
There are many ways to do so. The way we’ll do it here will involve dumping your boot.img
from a device or working ROM (for example stock). You can also just steal it off of a known working device tree if you want.
Dump your boot.img
and then run
unpack_bootimg.py --boot_img boot.img
This command will print your device Page Size. Note that down.
This is only needed if your device has a dtb partition. If it’s appended to the kernel this is not needed.
From the kernel building example above. Run:
PATH make dtbs -j$(nproc) O ARCH SUBARCH CC NM OBJCOPY LD LD_LIBRARY_PATH DEFCONFIG CLANG_TRIPLE CROSS_COMPILE CROSS_COMPILE_ARM32
This will generate your dtb
images.
To make dt.img
run:
cat $(shell find kernel/out/arch/<arch>/boot/dts/** -type f -name "*.dtb" | sort) > dt.img
From the kernel building example above. Run:
PATH make dtbs -j$(nproc) O ARCH SUBARCH CC NM OBJCOPY LD LD_LIBRARY_PATH DEFCONFIG CLANG_TRIPLE CROSS_COMPILE CROSS_COMPILE_ARM32
This will generate your dtbo
images.
To make dtbo.img
run:
./libufdt/utils/src/mkdtboimg.py create dtbo.img --page_size=<page_size> $(find kernel/out/arch/<arch>/boot/dts -type f -name "*.dtbo" | sort)
Further reading:
LLVM
and LLVM_IAS