The kernel is the basis of your Linux system. In fact, some people even say that the kernel is Linux and that everything else is just a bunch of Linux applications on top of the kernel. Whatever your point of view is, the bottom line is that, without the Linux kernel, you wouldn’t have Linux. In this article I’m going to look at what used to be one of the more daunting tasks for any Linux user: compiling the kernel.
Someday, you might have to compile your own kernel for any number of reasons. For instance, most distributions come with precompiled kernels; distributors compile them before packaging everything together. Since a distribution needs to service a wide range of hardware, many unnecessary device drivers (also called modules) and options are enabled, and some unusual options that you may need are disabled. Thus, you may have to compile your own kernel in order to disable those options that you don’t need and to enable those options that you do. Also, you may want to streamline your system. Often, compiling your own kernel results in a faster Linux system that’s specific to your computer.
Since there are a number of options that are available at compile time, a kernel that’s compiled on one computer may not work on another. If you decide to customize your kernel, you can do so in two ways. First, you can make it general enough to work with any computer that you have (though it might end up being similar to the distributor's precompiled kernel). Second, you can streamline it for a particular machine.
Back it up!
Before you begin to delve into the murky world of kernel compiling, you ought to make a backup of your system—at least back up your important configuration files and your old kernel. Kernel compilation is no easy task. Yes, it’s easier now than it used to be, but it’s still a tricky business. For someone who’s new to Linux or new to compiling kernels, it can become a trial-and-error ordeal. Thus, my words of wisdom: back up! You've been warned.
To compile a kernel, you need a few things. Most importantly, you need an existing Linux system into which you can boot. You also need the GNU C compiler, a recent version of LILO (0.19 or higher), root access on the computer that you’ll be using, and about 200 MB of free space. The more memory you have, the faster your compilation time will be. So, get as much memory as you can. Finally, you'll need the Linux kernel source code. You can download the source code in TAR format from the Linux Kernel Archives, or you can use the source code that comes with your distribution. It may be in a TAR/GZip archive, an RPM, or a DEB package, depending on your distribution.
When you’re looking for a kernel version, pay close attention to the version numbers. The first number is the release number, the second number is the version number, and the final number is the patch level. The version number will be an even or odd number; even stands for a production (stable) kernel, and odd stands for a development (possibly unstable) kernel. You’ll always want to use a production kernel—unless you need a special hardware device that’s only available in the development kernel. The patch level indicates minor improvements. So, when you’re selecting your kernel, pick the kernel with the highest patch level number.
Unpacking and moving in
The first step is to unarchive the source code. For this article, I’m using the 2.2.13 kernel under Linux Mandrake 6.1 on a PII-350 with 64 MB of RAM. Either you can install your RPM or DEB package, which will place the source files in their correct locations, or you can copy your TAR/GZip archive to the /usr/src directory. Extract the archive this way:
tar xvzf linux-2.2.13.tar.gz
Using this line will place the source code into the directory /usr/src/linux-2.2.13. Next, you’ll need to make a symbolic link from the /usr/src/linux-2.2.13 directory to the /usr/src/linux-2.2.13 directory by issuing:
ln -s /usr/src/linux-2.2.13 /usr/src/linux
This line will create the directory /usr/src/linux, which points to the /usr/src/linux-2.2.13 directory. Now that you have source code unarchived and your symbolic link in place, change your current directory to the /usr/src/linux directory and begin compiling your kernel.
Baby's first configuring steps
Now, you can configure the kernel. There are four ways to complete this task. You can use the traditional “make config” method, which results in a series of questions that are posed one line at a time. You can use make "menuconfig," which results in a curses-driven text-mode menu system. You can use "make xconfig," which launches an X GUI menu system. Finally, you can use "make oldconfig;" it’s similar to make config, but it retains the options that were used in the previous kernel compile—you don't have to restate answers for all of the questions that config asks. I strongly recommend that people who are new to compiling Linux kernels use either menuconfig or xconfig. That way, they’ll find the whole experience far less confusing.
Now that you’ve chosen how you want to configure the kernel, issue the appropriate make command. For this article, we'll use xconfig. In an xterm window, type:
The xconfig menu interface will appear. It contains a wide range of buttons that configure various parts of the kernel. If you select any section of the kernel configuration menu, you’ll enter a submenu that has even more options. The submenu is where you define what you want included, excluded, or made available as a module in the kernel.
On the left-hand side of the submenu, next to various kernel support items, you’ll see three columns of buttons with the letters Y, N, and M. Choosing Y means you want support for that particular item to be compiled directly into the kernel. Choosing N means you don’t want support for that item. Choosing M means you want support for that item to be compiled into the kernel but you also want the software for the item to be compiled into a separate module (device driver). There are a few ways in which you can go about deciding how you want things set up—whether you compile them into the kernel or set them up as modules. What you should keep in mind is that, if you don't use a device very often, you should load the device as a module. Doing so will free up system resources because you won’t be keeping support for a device in memory when it isn’t required. Instead, if you make the support available as a module, the kernel can load and unload the module when it requires support for a particular device. Using a kernel with support for modules is known as using a modular kernel, and it’s probably the most popular way of compiling kernels. Most distributions come with modular kernels because the kernels can support every device for which support exists. They don’t overwhelm the system by always keeping all of the software support for these devices in memory.
You can optimize your system and make it a little leaner for your computer. First, you should go into Code Maturity Level and disable prompting for development and incomplete code/drivers. This will prevent xconfig from asking you about experimental or unstable kernel drivers during configuration. Next, you’ll want to do is go into the Processor type and features section and select your processor type. The default setting is designed to compile for 386 computers. If you have a Pentium computer or better, however, you’ll want to compile for that architecture and make your system run faster by using optimized instructions for your CPU. You also should use your processor's advanced features, which probably aren’t available to 386 processors.
Other areas of importance include sections like Block Devices, Network Device Support, Filesystems, and Sound. By default, a number of network cards and devices are compiled into the kernel or made available through modules, but most people have installed only one or two network cards into any given computer. You can reduce some overhead by turning off support for the cards that you don’t use. You’ll want to enable ISO9660 and Joliet in Block Devices if you have a CD-ROM—and possibly some other file formats, such as NTFS or HPFS support, if you’re dual booting between Linux and Windows NT or OS/2. SCSI users will want to compile the kernel with SCSI support and to compile support for their SCSI adapter directly into the kernel. Doing so prevents any need for a RAM disk to start SCSI when the system boots. You also should compile support for your sound card directly into the kernel, instead of using a module. The more often a device or feature is used, the more convenient it is to compile support directly into the kernel.
In Character Devices, there are a number of options enabled by default that you’ll probably never need or use; disable them. In Native Language Support, you should disable support for all languages, except for the language that you use. Another section that needs to be cleaned up is Networking Options, where you can disable support for such protocols as AppleTalk or IPX. You need support for these protocols only if you’re networked to older Macintosh computers or to NetWare servers that don't use TCP/IP. You should compile support for routing and firewalls directly into the kernel, too; doing so prevents your system from becoming compromised on the Internet.
When you’ve finished making all of these changes, save your work and exit xconfig. Your new kernel configuration will be located in the file /usr/src/linux/.config. It’s a straight ASCII text file, which you can review with your favorite text editor—if you want to do so. If you find anything else that you need to change, simply run xconfig again.
An actual, factual compilation
Once you've verified your configuration, it's time to begin the actual compiling. Run make depend from the /usr/src/linux directory. This command tells the system to check file dependencies and resolve them; it guarantees a correct compilation. Next, type make clean. This command prepares the system for the kernel compiling. If there are any problems with your configuration or with the source itself, make will advise you during these two stages.
Finally, we’re ready to compile the kernel itself. Once you’re back to a root prompt, type make bzImage on the command line. This command compiles the kernel source. It can take a few minutes or a few hours to complete, depending on the amount of memory that’s available to the system and the speed of your processor. You also can issue make zImage. This command creates a zipped image file; it’s a self-extracting compressed file that gets loaded into your computer's low memory (the first 640 KB of RAM). Then, after the system is placed into protected mode, it gets uncompressed into high memory. The difference between zImage and bzImage is that bzImage is a big zImage file that gets loaded directly into high memory with special BIOS calls (and there’s no limit to the size of the image). In most cases, you’re better off using bzImage instead of zImage. You also can run make boot, which create an image that’s suitable for booting from a floppy diskette.
The next step is to compile the software for the modules that you want your new kernel to use. Switch to the /lib/modules directory and look for the subdirectory that’s called 2.2.13 (or whichever version of the kernel you’re using on your Linux system). Rename this directory to something like /lib/modules/2.2.13-old and then return to the /usr/src/linux directory. To compile the modules, run make modules. To install the modules into /lib/modules/2.2.13 (because we’re recompiling the 2.2.13 kernel), type make modules_install on the command line.
Now that we’ve compiled and installed our new modules, go to the new /lib/modules/2.2.13 directory and issue depmod -a. This command creates a list of module dependencies that indicate the order in which the kernel should load the modules (as they’re needed). Eventually, it creates a new file called /lib/modules/2.2.13/modules.dep.
Our friend LILO
If everything compiles successfully, you’ll have a new kernel called bzImage in the directory /usr/src/linux/arch/i386/boot. Copy this kernel to the /boot directory. Then, go to the /etc directory and use your favorite text editor to open lilo.conf. You’ll need to modify your LILO configuration in such a way that it allows you to boot from your new kernel. Rename your old kernel label and insert another image section for your new kernel. When you’re done with it, your LILO configuration might look something like this:
The above example illustrates a LILO configuration that has the option of booting into Windows. If no alternative is chosen, the first listed image section is the default boot option that will be loaded. We've made our new kernel the default boot option, but we've also made our old kernel available (it’s labeled linux-old)—just in case our new kernel doesn't work correctly. To get LILO to use the new configuration, run /sbin/lilo -v. It will tell you if there are any problems with your configuration. If all goes well, you'll be ready to reboot and to try out your new kernel.
After you make sure that there aren’t any users logged into the system and that no important tasks are running, you should reboot the system by running shutdown -r now. At the LILO prompt, press [Tab]. You’ll see your boot menu and, as boot options, the linux kernel and the linux-old kernel. Type linux (or the name that you gave to your new kernel), and your new kernel will load. Keep an eye out for any error messages or problems while you’re loading support for devices. If something goes horribly wrong and you can't boot with your new kernel, reboot or power down. Then, enter the name of your old kernel at the LILO prompt, enter the /usr/src/linux directory, and fire up make xconfig again.
Once you've made it to a login prompt, log in to the system and test various programs. Try pinging another computer, writing an e-mail message, starting X, making a call with your modem, and so on. If you see any error messages while you’re performing these normal tasks, go back and compile what’s missing into your kernel. Once you’ve used your new kernel for a while and you’re confident that it’s what you want (and you haven't discovered any hidden problems), you can delete the old kernel from the system and rely solely on your new kernel.
Compiling the kernel isn’t absolutely necessary. The precompiled kernel that ships with most distributions will probably do what you need it to do. Compiling kernels is a project for more adventurous users or for users who want to increase the efficiency of their systems by streamlining the kernel and by eliminating the options and software support that they don't need. Knowing how to compile your kernel will allow you to make your system more flexible and will help you stay current on new kernel versions that are becoming available. However, a number of distributions provide kernel updates that are easy to install and upgrade with RPM and DEB packaging methods. Of course, compiling your kernel lets you customize Linux to suit your individual tastes and needs. It also gives you an excellent overview of what can be done with Linux and what Linux supports.
Vincent Danen, a native Canadian in Edmonton, Alberta, has been computing since the age of 10, and he’s been using Linux for nearly two years. Prior to that, he used OS/2 exclusively for approximately four years. Vincent is a firm believer in the philosophy behind the Linux "revolution,” and heattempts to contribute to the Linux causein as many ways as possible—from his FreezerBurn Web site to building and submitting custom RPMs for the Linux Mandrake project. Vincent also has obtained his Linux administrator certification from Brainbench .He hopes to tackle the RHCE once it can be taken in Canada.The authors and editors have taken care in preparation of the content contained herein, but make no expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for any damages. Always have a verified backup before making any changes.
Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.