Building a Custom Kernel Out-Of-Tree

See also Custom Build Cross Arch

export DISTRO="ubuntu-gutsy"
export ARCH="x86_64"
export UBUNTU_ARCH="amd64"
mkdir -p ../builds/${DISTRO}
cat debian/config/${UBUNTU_ARCH}/config{,.generic} > ../builds/${DISTRO}/.config
make -j${CONCURRENCY_LEVEL} O=`pwd`/../builds/${DISTRO} oldconfig
make -j${CONCURRENCY_LEVEL} O=`pwd`/../builds/${DISTRO}

Important Note

If building for a different architecture than the current host CPU set the ARCH environmental variable explicitly otherwise the config scripts will use the host to determine it:

export ARCH="x86"

or pass it to make explicitly:

make ARCH=x86 O=`pwd`/../builds/$DISTRO menuconfig

If make complains that the directory isn't clean, and to run mrproper, it is likely there are local build remnants in the source directory - not the out-of-tree build directory so clean the source directory tree and then try the build again:

make mrproper

Installing modules and files needed to boot

# install modules to /lib/modules
sudo make O=`pwd`/../builds/${DISTRO} modules_install
export MY_VERSION="$(make O=`pwd`/../builds/${DISTRO} kernelrelease)"
# copy .config to /boot
sudo cp `pwd`/../builds/${DISTRO}/.config /boot/config-${MY_VERSION}
# copy to /boot
sudo cp `pwd`/../builds/${DISTRO}/ /boot/${MY_VERSION}
# copy compressed kernel Image (bzImage) to /boot
sudo cp `pwd`/../builds/${DISTRO}/arch/${ARCH}/boot/bzImage /boot/vmlinuz-${MY_VERSION}
# create and install initial root file-system ramdisk
sudo update-initramfs -c -k ${MY_VERSION}
# update the grub menu
sudo update-grub

Update: Automation

I have revised and improved the original script and called the new one (Out Of Tree Build Install). Now, from a common base directory the script is launched with a couple of variables preset and the final result is a new kernel installed and ready to boot. For example:

CONFIG="CURRENT" DISTRO="ubuntu-hardy" ./

The script will generate a system-beep at the point it asks permission to run the installation functions via sudo.

Setting CONFIG to CURRENT tells the script to use the existing .config file rather than copy a new one in or generate one using the default ubuntu configs and make oldconfig.

DISTRO tells the script which sub-directory from the base-directory to work in. In my development environment I have:


The script is in .../linux/ and so setting DISTRO to a sub-directory name sets everything up. The out-of-tree builds are done in .../linux/builds/${DISTRO}/

Once built the modules are installed, firmware links created, kernel files copied to /boot/, the initrd image created and finally the grub menu updated. The generated version will be a mainline kernel one, not Ubuntu, so for the hardy tree instead of 2.6.24-20-generic it will use Read the script source comments for more details of the options.