Kernel Compile -- step by step. ------------------------------------------------------------ Note: according to Linus (http://www.ussg.iu.edu/hypermail/linux/kernel/0007.3/0587.html) the directory '/usr/include/linux' must contain the headers that your current glibc was compiled with, not your current kernel. The document has been changed to relfect that. Note that Linus also recommends building a kernel inside your home directory. ------------------------------------------------------------ I will make a few assumptions here: [A1] You have a working linux install Compiling and installing a linux kernel from scratch on another OS is well beyond the topic of this (pitiful) HOWTO. You can visit the LFS home page to find out how to do that ;) . [A2] You are competent with the basic OS-utils and commands used throughout this HOWTO. You can at least use the man command to find out about commands that are new. [A3] You have a way to get stock kernel sources By "stock" I mean unmodified. No "-mdk" sources. (Yes, I had bad experiences when trying to configure and compile the mandrake kernel sources). Either they they are on your distro's CD's or you can get them from www.kernel.org . The file name should be in the form of: "linux-.tar.[bz2|gz]" ie: 'linux-2.4.20.tar.bz2'. [A4] You know how to compile and install programs The standard Linux Incantation: "./configure make root# make install " still applies, it's just a little more complicated: make xconfig make dep make modules make bzImage make modules_install make install If you have never compiled a program, i suggest trying a few. Take a look at compiling 'checkinstall' -- it is an excellent utility that will create a slackware/redhat/debian package from sources. [A5] You have a working (and easy to modify) boot loader or equivalent (LILO, GRUB). This is essential for testing your new kernel without making your system un-bootable. If you need a rescue CD, get knoppix, (www.knoppers.de), burn to a CD, and ensure you can boot from it. [A6] You either: know your hardware, have every important version number written down, and you understand what most of it means -- OR -- can locate your current kernel config file. Try "/boot/config"; keep in mind that this might be a symlink. [A7] You have a special user for kernel compiles; You can always do them as root, but you should not get into the habit of doing a bunch of things as root. You might mistype something eventually, thinking that you are a regular user, and a few megs will suddenly disappear from your HD.... you have been warned. [A8] You are willing to experament a little ;) . ------------------- And now I will make the following defines: [D1] 'root# ' means to perform this action as root. [D2] 'me$ ' means this action does not need to be done as root. It can be a regular user or one that is set up for kernel compiles. 'me' can belong to group "kernel-builder": a group that has no other members. If you aren't that paranoid (even I'm not) you can just use your normal login user, and normal group "users", or whatever group suits your security paradigm best (like wheel, for instance). [D3] everything past a '#' mark (except for the 'root# ' prompt) denotes a comment. You don't have to type them in; bash will ignore them anyway. [D4] I will be using kernel version 2.4.20; replace with the kernel version you are trying to build. [D5] Quoting: Since this is a (fairly) technical document, I have tried to use a consistent quoting style. Everything after a prompt (me$ or root#) should be typed in literally. This includes quotes and dollar signs. Single quotes (') are also literal. There is the problem with the English language: sentences must start with uppercase letters. gcc, although it is a valid command, cannot start a sentence without changing to Gcc; which for many of us accustomed to Unix-like syntax, can take a second or so to realize what those three letters stand for (GNU code compiler :) ). The above sentence is plain ugly; so I decided to uglify it some more. If I start a sentence with a unix name, I will enclose it in 'single quotes' for clarification. 'sentence' can be lowercase again, and yes, I did mean to end the sentance prior. There is also the problem of punctuation which can have disastrous consequences in 'vi'. Punctuation that is not a part of a unix name belongs outside of the quotes, if only for clarification and consistency. Back-quotes (`): A back-quote has special meaning in bash (and probably other shells as well): it means to take the output of the back-quoted command. For example: me$ ls -l `find ~ -name kernel-compile.txt` will do 'ls -l' on every file that 'find' returns. An alternative (bash) syntax would be: me$ ls -l $(find ~ -name kernel-compile.txt) I might get around to making that replacement. Note: Most of Europe uses what we silly Americans call "smart quotes", which is to say that the quotes should point in the direction of the ``quoted'' material. With just about any fixed- width font, this looks bad -- it is hard to see the preceding quotes, and the trailing ones do not have the complimentary angle: they are straight down. I never type in "smart quotes" so you shouldn't see them in here. Double Quotes ("): I use double quotes to refer to something that may need a little substitution, like "linux-.tar.bz2". There also might be some variation depending on your setup, so poke around a little. For example, "/boot/config" might be '/boot/config.gz', in which case you will need to 'gunzip' it first. Angle Brackets (< >): Text between these markers should be substituted with something sane; but only inside double quotes. Misc: [SAVE] is a button in a GUI or on the keyboard, (!)this(!) means "shouting" text, and //this// is stressed text. ------------------- PROLOGUE: Do not perform the steps in EPILOGUE if you do not perform these. '/boot': To make life saner (if not easier), I recommend the following actions to correctly label your current kernel and related files: root# cd /boot root# mv System.map System.map-`uname -r` root# mv bzImage bzImage-`uname -r` root# mv config config-`uname -r` As you can see, my naming scheme is fairly transparent: the file name followed by the kernel version. You might find that your current kernel is '/vmlinuz', or that you have no 'System.map' or 'config'. Make changes as appropriate. ------------------------------ OK, so you got this file called 'linux-2.4.20.tar.bz2'... what do you do with it? ______________________________ STEP I - unpacking the sources me$ su password: root# ln linux-2.4.20.tar.bz2 /usr/src # kernel sources live in '/usr/src/'. root# cd /usr/src root# tar -jxf linux-*.bz2 # un-tarball it. root# chown -R .kernel-builder linux-2.4.20 # Prep the directory so we can let go of root# chmod -R g+rwX linux-2.4.20 # root privlages ASAP. root# rm linux-2.4.20.tar.bz2 # Not really neccessary, just reduces clutter. root# exit me$ cd /usr/src/linux-2.4.20 me$ cp /boot/config .config Remember that '/usr/src/linux/.config' is what the kernel config is based on, but will be removed if we do a 'make mrproper'. ______________________________ STEP II(A) - Naming the Kernel You might think that this is fluff, but it is actually very important. If you have a working kernel of the same version as the one you are currently compiling, this step is absolutely vital! Here are a few lines from the Makefile: VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 EXTRAVERSION = KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) So you see where the kernel gets its name, right? For the stock bare kernel, it is "2.4.20". All you need to do is set the EXTRAVERSION to something. Since I compiled my kernel for slackware, i edited that line to read 'EXTRAVERSION = -s.1' Mandrake 9 (M/9) has this set to "-16mdk". In any event the entire string "2.4.20-s.1" is returned when I type "uname -r". For redhat it is something like "2.4.18-16-RH8.0". It is also important that the EXTRAVERSION start with a '-'. See EPILOGUE for details. So why is the name important? simply put: when you build a new kernel you must build new modules to go with them. Even if you are building the same kernel version as the one you are running, mucking around with the configuration changes the internal structure of the kernel, and the modules must know before hand exactly what this structure is. And the kernel modules live in "/lib/modules/$KERNELRELEASE". Do 'ls -l /lib/modules' and you will see the top level directory for each kernel that was installed on your system. So, if you install a new module set for the same kernel version as your currently working kernel, //you will obliterate your working modules and possibly break your current kernel.// ______________________________ STEP II(B) - Prep the Sources This step is unneccessary if you just unpacked the tarball. If you are having another go at compiling the same kernel sources, you (!)must(!) run: me$ cp .config config.sv # save yer hard work me$ make mrproper # clean up mess me$ mv config.sv .config # reset hard work to clean up the last disaster. ______________________________ STEP II(C) - Configuring the Kernel OK, now we have three different choices on how to run the configuration. If you are a GUI-kid (like me) you will be in your favorite window manager and terminal emulator the entire time. In that case you can do: me$ make xconfig and use the tcl/tk X Windows interface for configuring your kernel. Start with the first one and click the [NEXT] button to go thru all the options. Most of it should be already set up correctly (assuming that /boot/config contained your current kernel's config), and you should only need to make a few edits here and there. Things like the compiled in file systems if you plan on moving to a new file system, or a compiled in CD-ROM driver and initrd support if you want to boot from CD-ROM. Don't forget to save your work when exiting: [Save and Exit]. The saved config is named ".config". On the other hand, if you aren't running X, you can get a crude menu based CUI (Console User Interface) by: me$ make menuconfig If you feel like punishing yourself, you can go thru the configuration line by bloody line with: me$ make config But that looks like hell. Or at least purgatory. In any event, you (!)must(!) "make" a "config" and save the config before you will be able to compile anything. Even if you do not make any changes to the .config file, you must make a config or the next step will fail. BTW: I suggest taking a look at each config method to see which one suits you best. I prefer "make xconfig", but I noticed that most people will say "make menuconfig"; just FYI. ______________________________ STEP III - Dependencies me$ make dep OK, so what does that do? This step gets all the references between the kernel and it's associated modules sorted out. It creates text files that dictate what modules depend on other modules, and a 'System.map' file that can be used to verify that the modules belong to the correct build of the kernel. If you get make errors on this step, then you might have configured something wrong, and you must restart with STEP II(B). Try reconfiguring the relevent part of the kernel. This step should go without a hitch if you grabbed stock kernel sources. NOTE: If you don't plan on having yourself logged in to X while awaiting the compiles, you can always use the console by pressing [CTRL][ALT] and one of the [F?] buttons. Try them all, it can't hurt (slackware only keeps console 4 open when booting to the X windows runlevel; I think Red Hat keeps them all open). To get back to the GUI, press [ALT][F7]. You may now safely kill X Windows and not interrupt the compile. Just don't change runlevels.... ______________________________ STEP IV - Build Modules me$ make modules This is the section that will most likely cause you to pull out your hair. It is this section that the M/9 sources puke on the most. And this is why I say you need to get //stock// sources. This section should also go without a hitch. Again, if you get errors, start over from STEP II(B). ______________________________ STEP V - Build the Kernel There are two variations to this command; one is for systems that experience heavy load fluctuations, and looks like this: me$ nohup make & # prevent interruptions to "make" me$ tail -f nohup.out # see the progress of "make" The other version simply doesn't use nohup. me$ make If you think that your system might choke on resources, exit X Windows before running the commands. You can also either drop the X server if you are not using the GUI bootup runlevel, or 'root# telinit 3' if your comp boots to X Windows. To get back to the GUI login, 'root# telinit 4' or 'root# telinit 5' depending on your distro (RH and M/9 use '5'). I haven't used a nohup for a while now, and I usually surf the web and listen to music while I'm compiling a kernel. And I have an AMD Duron 750. Your Mileage May Vary. If you get errors in the compile, quit the "tail -f" with a [CTRL][C], and (yup, you guessed it) start over at STEP II(B). ______________________________ STEP VI - Compress the Kernel me$ make bzImage You might get some errors pertaining to the resultant kernel not fitting on a floppy if you compiled a lot of stuff in there. There is a price to pay for having a swiss army kernel. If there is no reason you will need to copy the kernel to a floppy, there is nothing to worry about. Heck, even in some cases there is nothing to worry about because I think that that error message assumes that you want to fit the kernel onto a floppy that has a file system on it, not simply 'dd' it there. In any event, onward. ______________________________ STEP VII - Install Modules root# make modules_install There should be no reason that you get errors in this section. What this does is move all the compiled modules to "/lib/modules/$KERNELRELEASE". You should be able to 'ls -l /lib/modules' and see "2.4.20-s.1" or whatever you named your kernel to, as well as the current 'uname -r' for your current kernel. ______________________________ STEP VIII - Install the Kernel There's the quick way: root# make install But be prepared for this to wipe out your current kernel in /boot, not to mention your System.map. What this does may depend on the distro. This is the way to do it by hand: root# cd /usr/src/linux root# cd arch/i386/boot # This is where the new bzImage is created root# cp bzImage /boot/bzImage-2.4.20-s.1 # Compressed kernel. # Note that there is an "install.sh"; you # might want to have a look at it. root# cd ../../.. # /usr/src/linux again root# cp System.map /boot/System.map-2.4.20-s.1 # Keep the System.map and root# cp .config /boot/config-2.4.20-s.1 # the config for future reference. What is System.map you ask? Simply put it is a list of pointers inside the kernel so that loadable modules know how to reference the rest of the kernel. This is part of the magic of "make dep", and it is necessary to have a System.map file in /boot if you ever need to add a pre-compiled module (rare), use a root-kit checking utility, or need to run 'depmod' for a kernel that is not your current kernel. ______________________________ EPILOGUE - Boot Setup This only need be done once, and only if you followed my advice in 'PROLOGUE'. Performing these steps without performing the steps in PROLOGUE may delete your current kernel upon reboot. Create a startup script that symlinks each of the kernel files to the generic name. I recommend /etc/rc.d/rc.local (BSD init style) in lieu of creating the script from scratch: mount -o remount,rw /boot # Only needed if /boot is mounted "ro". rm -f /boot/System.map /boot/config /boot/bzImage # Delete (possibly) stale symlinks. kver=`uname -r` # Grab our compiled in kernel name. ln -s System.map-$kver System.map # Point our current kernel's files ln -s bzImage-$kver bzImage # for easy reference. ln -s config-$kver config mount -o remount,ro /boot # Only if you want /boot mounted "ro". rm -f /lib/modules/linux # Just for ease of reference. ln -s /lib/modules/$kver /lib/modules/linux I don't know the equivalent script for SysV style inits (just about everything but slackware); but I think it's "/etc/init.d/local". It shouldn't be too hard to find tho; try 'ls -l /etc/rc?.d/*local*'. ______________________________ And that's all there is too it. All that is left is editing GRUB / LILO to try out yer new kernel. If it doesn't quite work, don't get discouraged. I had to recompile my kernel 15 times to get it right initially. But you shouldn't have too many problems if you are using //stock// sources, and you can find your current config file. -t.