5.3 Compiling the Kernel

Compiling the kernel involves a number of steps: building the kernel dependencies, building the kernel image, and building the kernel modules. Each step uses a separate make command and is described separately in this section. However, you could also carry out all these steps using a single command line.

5.3.1 Building Dependencies

Most files in the kernel's sources depend on a number of header files. To build the kernel adequately, the kernel's Makefiles need to know about these dependencies. For each subdirectory in the kernel tree, a hidden .depend file is created during the dependencies build. This contains the list of header files that each file in the directory depends on. As with other software that relies on make, only the files that depend on a header that changed since the last build will need to be recompiled when a kernel is rebuilt.

From the kernel source's root directory, the following command builds the kernel's dependencies:

$ make ARCH=arm CROSS_COMPILE=arm-linux- clean dep

As in the configuration of the kernel earlier, we set the ARCH and CROSS_COMPILE variables. As I explained in Chapter 4, CROSS_COMPILE is only required when source code is actually compiled, and could be omitted here. On the other hand, we will need to set at least the ARCH variable for every make command we issue because we are cross-compiling the kernel. Even when issuing make clean or make distclean, we will need to set this variable. Otherwise, the kernel's Makefiles assume that the operations are to be carried out for the kernel code related to the host's architecture.

The ARCH variable indicates the architecture for which this kernel is built. This variable is used by the kernel Makefiles to choose which architecture-dependent directory is going to be used. When compiling the kernel for your target, you must set this variable to your target's architecture.

The CROSS_COMPILE variable is used by the kernel's Makefiles to construct the names of the tools used in the kernel's build. The name of the C compiler, for instance, is the result of the concatenation of the value of CROSS_COMPILE and the letters "gcc". In the case of our ARM target, the C compiler's final name is arm-linux-gcc, which is the actual name of the compiler we built for this target using the instructions in Chapter 4. This also explains why the trailing hyphen on the previous command line is important. Without this hyphen, the Makefile would try to use the arm-linuxgcc compiler, which doesn't exist.

The building of the dependencies is relatively short. On my PowerBook, this takes two minutes. There are usually no errors possible at this stage. If you do see errors, the kernel you have probably suffers from fundamental problems.

5.3.2 Building the Kernel

With the dependencies built, we can now compile the kernel image:

$ make ARCH=arm CROSS_COMPILE=arm-linux- zImage

The zImage target instructs the Makefile to build a kernel image that is compressed using the gzip algorithm.[4] There are, nevertheless, other ways to build a kernel image. The vmlinux target instructs the Makefile to build only the uncompressed image. Note that this image is generated even when a compressed image is requested.

[4] Though zImage is a valid Makefile target for all the architectures we discussed in depth in Chapter 3, there are other Linux architectures for which it isn't valid.

On the x86, there is also the bzImage target. The "bzImage" name stands for "big zImage," and has nothing to do with the bzip2 compression utility. In fact, both the bzImage and zImage Makefile targets rely on the gzip algorithm. The difference between the two Makefile targets is that the compressed kernel images generated using zImage cannot be larger than 512 KB, while those generated using bzImage are not bound by this limit. If you want more information regarding the differences between zImage and bzImage, have a look at the Documentation/i386/boot.txt file included in the kernel sources.

If you chose any options not supported by your architecture during the kernel configuration or if some kernel option is broken, your build will fail at this stage. If all goes well, this should take a few minutes longer than the dependency build. On my hardware configuration, it takes five minutes.

Verifying the Cross-Development Toolchain

Notice that the kernel build is the first real test for the cross-development tools we built in the previous chapter. If the tools you built earlier compile a functional kernel successfully, all the other software should build perfectly. Of course, you will need to download the kernel you built to your target to verify its functionality, but the fact that it builds properly is already a positive sign.

5.3.3 Building the Modules

With the kernel image properly built, we can now build the kernel modules:

$ make ARCH=arm CROSS_COMPILE=arm-linux- modules

The duration of this stage depends largely on the number of kernel options you chose to build as modules instead of having linked as part of the main kernel image. This stage is seldom longer than the build of the kernel image. As with the kernel image, if your configuration is inadequate for your target or if a feature is broken, this stage of the build may fail.

With both the kernel image and the kernel modules now built, we are ready to install them for our target. Before we do so, note that if you needed to clean up the kernel's sources and return them to their initial state prior to any configuration, dependency building, or compilation, you could use the following command:

$ make ARCH=arm CROSS_COMPILE=arm-linux- distclean

Be sure to backup your kernel configuration file prior to using this command, since make distclean erases all the files generated during the previous stages, including the .config file, all object files, and the kernel images.