Integrated Kernel Building

Why does CM want the kernel built together with Android?

Before CM9, we depended on having prebuilt kernels in every device repository. These were compiled separately from the framework and required the device maintainer to manually update the kernel image and modules any time a change is done. In addition, kernels were not using a consistent naming scheme, many were not managed by the CyanogenMod Gerrit, and were often compiled using compilers other than the one found in the Android toolchain. This has lead to major inconsistencies, and difficulty for others to match the maintainers build. [More info here]

Note:

Check the The CyanogenMod Learning Center to learn more about CyanogenMod building, and especially the Envsetup help for a list of build commands.

How to (edit and) build an officially supported kernel?

Option A: Building the full ROM (Kernel + Android) from the full CyanogenMod source

Follow the CM Build Guides for your device.
The kernel sources will be automatically downloaded if your device is supported. The ROM will be built into a ClockworkMod Recovery flashable zip file.
Note that the full CM Android and Kernel source will be downloaded (several GB) and along with the build files you will need ~40-50GB (for CM11.0, depends on your kernel) of disk space.

Option B: Building only the Kernel from the full CyanogenMod source

Follow the CM Build Guides for your device with the change explained below.
Your device kernel will be downloaded during the launch of the breakfast or lunch command as described in the build guide. Note that the full CM Android and Kernel source will be downloaded (several GB) and along with the build files you will need ~20GB (for CM11.0, depends on your kernel) of disk space.

So follow your device build guide but instead of:

$ brunch

run (also from the CM Android source root directory (croot), not from the kernel directory):

$ mka bootimage

This will only compile the kernel source into a boot.img. You will therefore save a lot of compilation time.
The boot.img file can be then flashed with fastboot or directly from the command line.
Note that to ensure kernel – ROM compatibility, your phone should run a ROM based on the same kernel version that you’re flashing, or things may break.

$ adb root
$ adb remount
$ installboot
$ adb reboot

Note: If your device supports fastboot (Samsung doesn’t), you can test the kernel instead of flashing it:

$ adb reboot bootloader
$ fastboot boot "$OUT/boot.img"
Changing the kernel configuration

The kernel configuration file used during the build process is referenced in TARGET_KERNEL_CONFIG variable in device/vendor-name/device-name/BoardConfig.mk. It generally points to kernel/vendor-name/kernel-name/arch/arm/configs/cyanogenmod_device-name_deconfig.

To make a custom kernel configuration file, you can use the configuration build tools from the kernel dir, e.g. make menuconfig, and save the resulting hidden .config file to the location specified in TARGET_KERNEL_CONFIG. Then run make mrproper from the kernel dir and go back to the CM android source root dir (croot) before building.

Re-building

To re-build the kernel after you’ve made some changes to the source files or config file, just run mka bootimage again. The build will be much faster due to caching, and selective build of modified files. Beware the errors during the re-build process: the building system may use previously built object/modules if some objects fail to build, leading to inconsistencies. In case of doubt, run mka clean.

Note that you can’t use mm‘s command for kernel modules. These commands are made for modules that use an Android.mk file and not a standard Makefile, like system (not kernel) modules.

Helpful Tip

Escaping a bootloop: If your device is stuck in a bootloop after flashing, flash again the device with a working kernel (or in the worst case with a full ROM / nandroid backup).

In your build directory, you can find the kernel zImage in $OUT/obj/KERNEL_OBJ/arch/arm/boot. This file can be flashed on supported devices with Heimdall (for some Samsung devices) or fastboot (for devices supporting fastboot mode).

Note that however, mka bootimage doesn’t generate a ClockWordMod or TWRP flashable zip file, you will have to build it yourself if you can’t use the zImage directly.

TO AVOID: Building only the kernel from the kernel source

As of CyanogenMod 9, we are deprecating the usage of prebuilt kernel images. The build system has been modified to ask for (and build) the kernel source. So don’t follow CM oldwiki kernel build guide.

Building an official kernel from the CyanogenMod build system will ensure your are using the proper Android toolchain. It will also bring more guarantee of compatibility between the kernel and the userspace (system calls, like ioctl, should be consistent between the kernel and userspace).

Moreover, the kernel Makefile generally doesn’t take care of creating the device-specific ramdisk, embedding the kernel image (zImage) and ramdisk into a boot.img (which structure is sometimes device specific) and pushing everything, including the loadable kernel modules, to the device. Whereas by building from the full CM source, the CM build tools will automate these steps.

TO AVOID: Building only a kernel module and importing it on a different kernel version

Kernel modules (e.g. a Wi-Fi driver) are built for a specific kernel version. Indeed, the kernel module (.ko file) embed the version of the kernel it is built for (check modinfo module-name.ko). The module will not load if its version is different than the running kernel version (check uname -a from the device terminal prompt). One reason behind this version interdependency is that internal interfaces within the kernel (the interfaces used in your module to access other kernel resources/modules) can and do change between versions. [source: LKMPG]

Therefore you should build and flash a full kernel if you need to change a module.

Otherwise, and if you make no kernel configuration change, you can build a kernel module from the same exact kernel source version (i.e. Github commit) that you’re planning to import the module into. If you’ve not built the kernel yourself, this becomes highly complicated and deprecated: you may need to rebase your CM repository to the exact Github commit that your kernel was built from, extract and use the .config from your device, and eventually trick the source files that take care of defining the magic version of the built kernel module.

How to reference a custom kernel for building?

This chapter is intended for people that want to use a totally different kernel than the officially supported ones.
If you only need to modify an officially supported firmware, go back to the previous chapter and play with the kernel files in kernel/vendor-name/kernel-name (the official kernel files for your device will be downloaded after running the breakfast or lunch commands as described in the Build Guides).

Step 0. Preparing the build environment

Depending on whether your device is supported or not, follow the Build Guides or Porting Guide to prepare the Build Environment and get CM Android source code, prebuilt apps, device-specific code and proprietary blobs.

Step 1. Deploying the kernel source at the proper location

The minimal requirement is that the kernel’s source tree for that device be present at kernel/vendor-name/device-name of the CM Android source.

  • Officially supported devices:
    • For devices which are part of mainline CyanogenMod and have their kernels in CM’s github, this can be accomplished by usage of CyanogenMod’s roomservice feature. Create a device/vendor-name/device-name/cm.dependencies file (if it doesn’t exist yet), with the following syntax. This will take care of downloading the source automatically into the right location.
[
 {
   "repository": "name-of-repository-in-the-CyanogenMod-github",
   "target_path": "kernel/vendor-name/device-name",
   "branch": "name-of-branch"
 }
]
  • Work-in-progress, unofficial, or otherwise non-integrated devices:
    • For devices which don’t have their kernel source at the CM github, usage of local_manifest.xml is recommended in order to deploy the source at the right location, and keeping it synchronized.
  • Devices using shared kernel repositories:
    • If your device shares a kernel with others, the default kernel/vendor-name/device-name path will lead to unnecessary duplication of source trees, so usage of the TARGET_KERNEL_SOURCE configuration variable in device/vendor-name/device-name/BoardConfig.mk is advised. All devices sharing that source should have the following line in their BoardConfig.mk files:
TARGET_KERNEL_SOURCE := kernel/vendor-name/unique-shared-source-name

Step 2. Configuring the device to build the kernel

After the source is in place, configuration of the device to build the kernel is trivial. Just add the TARGET_KERNEL_CONFIG variable to your device/vendor-name/device-name/BoardConfig.mk file, pointing to the configuration file name for your device (as present in kernel/vendor-name/kernel-name/arch/arm/configs). For example:

TARGET_KERNEL_CONFIG := cyanogenmod_device-name_defconfig

This will trigger the full kernel build, including the modules (if present) as specified in that configuration. Any modules built will be deployed at /system/lib/modules/ in the final image

If your device requires uImage, also ensure the following is present in your ‘BoardConfig.mk’

BOARD_USES_UBOOT := true

Step 3. Configuring the build of out-of-tree kernel modules

If your device needs modules that aren’t part of the kernel source tree, those can also be built automatically. Some hardware (Texas Instruments’ TIWLAN adapters, Broadcom’s BCM adapters) is directly supported by CM repositories, but if that isn’t your case we suggest you add your module’s source to either your device repository, or an isolated path in your kernel source.

To build these modules, the TARGET_KERNEL_MODULES variable can be used, pointing to a make target that will build and install such modules. Definition of such a target is the device author’s responsibility, the only restriction is that it is a normal makefile recipe. To include, for example, the TI WLAN modules, this can be used:

TIWLAN_MODULES:
       make -C hardware/ti/wlan/wl1283/platforms/os/linux/ KERNEL_DIR=$(KERNEL_OUT) ARCH="arm" CROSS_COMPILE="arm-eabi-" TNETW=1273 RANDOM_MAC=n REPORT_LOG=n
       mv hardware/ti/wlan/wl1283/platforms/os/linux/tiwlan_drv.ko $(KERNEL_MODULES_OUT)
       make -C hardware/ti/wlan/wl1283_softAP/platforms/os/linux/ KERNEL_DIR=$(KERNEL_OUT) ARCH="arm" CROSS_COMPILE="arm-eabi-" TNETW=1273 REPORT_LOG=n
       mv hardware/ti/wlan/wl1283_softAP/platforms/os/linux/tiap_drv.ko $(KERNEL_MODULES_OUT)
    
TARGET_KERNEL_MODULES := TIWLAN_MODULES

As a rule of thumb, you can just paste your current standalone build commands into a make recipe, replacing the kernel source path with the $(KERNEL_OUT) variable.

Step 4. Configuring the fallback to prebuilts

If for some reason the kernel source can’t be present, you can still fall back to prebuilt binaries, by defining the TARGET_PREBUILT_KERNEL variable, like this:

TARGET_PREBUILT_KERNEL := device/vendor-name/device-name/kernel

Step 5. Building the kernel or full ROM

Now that your custom kernel is linked to your device, you can build the device kernel or the device full ROM as you would do with an official kernel, as described in the first part of this page.

Full configuration example

The following is the p920’s configuration (device/vendor-name/device-name/BoardConfig.mk), which attempts to build the kernel, uses external modules, and has a prebuilt fallback:

# Try to build the kernel
TARGET_KERNEL_CONFIG := cyanogenmod_cosmo_defconfig
# Keep this as a fallback
TARGET_PREBUILT_KERNEL := device/lge/p920/kernel

KERNEL_EXTERNAL_MODULES:
make -C hardware/ti/wlan/wl1283/platforms/os/linux/ KERNEL_DIR=$(KERNEL_OUT) ARCH="arm" CROSS_COMPILE="arm-eabi-" TNETW=1273 RANDOM_MAC=n REPORT_LOG=n
mv hardware/ti/wlan/wl1283/platforms/os/linux/tiwlan_drv.ko $(KERNEL_MODULES_OUT)
make -C hardware/ti/wlan/wl1283_softAP/platforms/os/linux/ KERNEL_DIR=$(KERNEL_OUT) ARCH="arm" CROSS_COMPILE="arm-eabi-" TNETW=1273 REPORT_LOG=n
mv hardware/ti/wlan/wl1283_softAP/platforms/os/linux/tiap_drv.ko $(KERNEL_MODULES_OUT)

TARGET_KERNEL_MODULES := KERNEL_EXTERNAL_MODULES

See also

Content of this page is based on informations from wiki.cyanogenmod.org, under CC BY-SA 3.0 licence.