Step-by-step Cross-compiling a Kernel

From odroid US
Revision as of 20:44, 18 March 2013 by Osterluk (Talk | contribs) (Grabbing the Kernel Source)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

This tutorial is for developers, primarily for those interested in Debian/Ubuntu systems. The techniques may be used to generate a kernel for Android systems, but the specifics of how the kernel and kernel modules are placed on the media would be different.


These procedures assume you have an Debian-based distribution loaded on your host and your odroid. Kernel building is not different between the distros, but getting ready to build is.

Debian/Ubuntu/Mint and others use "Debian packages", .deb files. They use tools like dpkg, apt, synaptic and so on to manage a package database.

RedHat, Centos, Fedora and Gentoo would not know about apt-get and friends -- so these instructions will not be of much use.

This tutorial has not been tested on a clean machine. There may be steps you need to do to set up for a build. You might need to install packages on your host to be able to build -- like build-essentials.


  • You do not need access to the serial console
  • You need to be able to copy or move files between the host and the odroid


    We are going to:

  • Install a specific toolchain on the host
  • Set up ccache, the C compiler cache
  • Set required environment variables
  • Get a snapshot of the Hardkernel kernel source and configure it
  • Build the kernel and kernel modules
  • Make sure the boot partition is mounted
  • Copy the build results to the odroid
  • reboot and check the kernel version

    Setting up the Toolchain

    If you are happy with your arm cross-compiler, you can skip this step. Some people prefer the CodeSourcery toolchains, but the free version does not support hard floating point.

    The kernel is much easier to build than a whole root file system because there are few dependencies. We need a compiler that can generate code for the cortex-a9. We prefer hard-float (armhf rather than armel in Debian lingo)

    On your Linux host, setup a shared work area

    sudo mkdir -p /usr/local/arm >/dev/null 
    sudo chmod 777 /usr/local/arm
    cd /usr/local/arm

    On your Linux host, get the toolchain and expand it.

    cd /usr/local/arm
    xz -d gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux.tar.xz 
    tar -xvf gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux.tar

    I need to change compilers depending on the project I'm working on, so I prefer to use a symlink to select the 'active' version.

    ln -s gcc-linaro-arm-linux-gnueabihf-4.7-2013.01-20130125_linux /usr/local/arm/toolchain

    Setup the c-compiler cache (optional)

    cd /usr/local/arm/toolchain
    mkdir bin-ccache
    # you may already have ccache installed, but for the sake of illustration...
    sudo apt-get install ccache
    ln -s $(which ccache) arm-linux-gnueabihf-gcc
    ln -s $(which ccache) arm-linux-gnueabihf-g++
    ln -s $(which ccache) arm-linux-gnueabihf-cpp
    ln -s $(which ccache) arm-linux-gnueabihf-c++

    Set Environment Variables

    It is convenient to edit your ~/.bashrc file and re-launch a shell rather than just export. That way, any session you start will have them already set. Some people prefer not to set these variable because it can cause x86 builds to fail. VMWare will fail to build kernel modules if you have CROSS_COMPILE and/or ARCH set -- try to remember that you set these variables.

    Add the bin-ccache directory in front of the toolchain/bin directory in the PATH

    export PATH=/usr/local/arm/toolchain/bin-ccache:/usr/local/arm/toolchain/bin:$PATH
    export CROSS_COMPILE=arm-linux-gnueabihf-
    export ARCH=arm

    Grabbing the Kernel Source

    Go to a convenient work area, here I show $HOME/work

    cd $HOME
    mkdir work
    cd work

    You can get the latest kernel snapshot or get a source for a specific Hardkernel released build. This link shows how to get a specific release: Use git and commit tag . If a snapshot is acceptable, use the wget step as shown next.

    Get the kernel snapshot, and unzip it

    wget --no-check-certificate

    Prepare to Build

    Move into the kernel source directory, select the configuration you want, and build it (you can see the alternatives in ./arch/arm/configs/odroid*)

    cd linux-odroid-3.0.y/
    make odroidu2_ubuntu_defconfig 
    make -j8 zImage


    make -j8 zImage
    make -j8 modules

    Make a directory for the kernel modules and let the kernel make system strip and copy them out. Create a tarball for quick copy/transfer.

    mkdir ../rfs
    export INSTALL_MOD_PATH=$PWD/../rfs
    make modules_install
    cd ../rfs
    # remove symlinks that point to files we do not need in root file system
    find . -name source | xargs rm
    find . -name build | xargs rm
    # Compress
    sudo tar -cvzf ../modules.tgz .
    cd ../

    Mounting the Boot Partition

    The boot partition is the section on the media, either SD-Card or eMMC, that holds the kernel image and the initial root filesystem. For the Hardkernel Ubuntu systems, the boot partition would be mounted at /media/boot. For other distros, the boot partition may not be mounted automatically and by default if might like to be mounted to a different location. For example, the Debian Wheezy distro does not currently mount it, and this and other tutorials mount it at /boot when necessary.

    You can work the tutorial and substitute /boot/media for /boot if you like, although it will not cause a problem if you just use /boot. Create the /boot directory to use as a mount point if you need to.

    This code snippet shows one way to mount the boot partition

        if [ ! -d /boot ]; then
            mkdir -p /boot || exit 1
        mountpoint /boot >/dev/null
        if [ $? -ne 0 ]; then
            mount -o rw /dev/mmcblk0p1 /boot || exit 1

    Copying the Build Results

    Copy our new kernel and modules to the target. This method copies over the network. The thing to remember is that the kernel goes on the boot partition and the kernel modules go on the rootfs partition. Here odroidu2 is the name of my odroid target, defined in /etc/hosts. You can do ifconfig on your odroid to see what IP Address it is using and then use it explicitly instead of the technique I show here (the dotted quad instead of odroidu2)

    scp modules.tgz root@odroidu2:/
    scp linux-odroid-3.0.y/arch/arm/boot/zImage  root@odroidu2:/boot

    Now go to the odroid Linux console, expand the kernel modules tarball and reboot

    tar -xvzf modules.tgz 
    rm modules.tgz

    Checking the Kernel Version

    Check the kernel version, with uname -a

    Linux odroidu2-1 3.0.61 #1 SMP Sat Feb 2 15:28:35 PST 2013 armv7l GNU/Linux