Recall that, during the course of your very first lesson, you managed to:
Recall, as well, that that last kernel "installation" step will, for any Linux distribution, inevitably consist of the following general steps, however they're accomplished:
vmlinuz-*compressed kernel image and a corresponding
initrd-*initial ramdisk image into the
All incredibly straightforward, so what else is there to know about this? I'm glad you asked.
(Aside: I won't always be available to immediately address questions people leave in the comments section so I'm going to reiterate -- use the comments section to chat and ask each other questions. Make this interactive. That's part of the learning process.)
Recall that, back in Lesson 1, we cheated a little bit and didn't spend a lot of time actually configuring our new kernel source -- we played it safe and simply used, as a template, an existing config file that came with the initial OS installation.
Once you've done that, though, and you've established that you can build and boot a new kernel based on that, the next obvious step is to invoke one of the kernel configuration targets, say:
$ make menuconfig
and spend some time poking around for obvious reasons -- that's where you'll get a good idea of how many choices you have in building a new kernel. I won't spend much time going over all of the possible choices for kernel feature selection. Again, I'll recommend Greg Kroah-Hartman's excellent book Linux Kernel in a Nutshell. However, I will treat you to one handy feature of the config process.
Occasionally, you'll read advice that says that to build in, for example, the "kexec" feature, you should select the CONFIG_KEXEC config variable, which is terrific if you happen to know where in the murky depths of the configuration menus that variable happens to live.
If you don't though, no problem -- simply start the configuration utility and search for the string by typing:
/kexec [slash, followed by string of interest, then ENTER]
What you get back is a list of every single kernel option containing that text string, and its location in the menu structure. Very handy indeed. Why you would select that particular feature and what you'd do with it -- well, that's the topic for a future lesson. I'm just showing you how the search feature works.
maketargets and pre-defined configurations
In case you hadn't figured it out by now, almost all kernel tree configuration is done through the top-level
Makefile by invoking one of its numerous targets, the entire list of which can be displayed with:
$ make help
Perhaps the most useful target for beginners is
defconfig (short for "default config") which simply sets your
.config to an established set of defaults for your system and architecture. And how can you see these defaults? Simple -- from the top of the kernel source tree, just run:
$ find arch -name "*defconfig"
and you'll see dozens of default config files for all of the kernel's supported architectures. Assuming you're working on an x86-like architecture, you're probably interested only in these:
$ find arch/x86 -name "*defconfig" arch/x86/configs/x86_64_defconfig [64-bit version] arch/x86/configs/i386_defconfig [32-bit version] $
In addition, running
make help shows you some other rather odd configuration targets:
... Configuration targets: ... randconfig - New config with random answer to all options defconfig - New config with default answer to all options allmodconfig - New config selecting modules when possible allyesconfig - New config where all options are accepted with yes allnoconfig - New config where all options are answered with no ...
Those targets are certainly a bit unusual, and you might wonder why anyone would configure a kernel so strangely. Actually, those targets have value for stress-testing the build process. It's not enough to verify that the kernel can build for typical configurations; it's good practise to see if those extreme corner cases also build. Feel free to configure your kernel tree with one of them and see if the build actually works.
If you want more output during the kernel and module compilation stage, running
make help shows you how to get that and also how to do static code analysis on the source if you're interested in that sort of thing:
... make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build make V=2 [targets] 2 => give reason for rebuild of target ... make C=1 [targets] Check all c source with $CHECK (sparse by default) make C=2 [targets] Force check of all c source with $CHECK
If you're simply playing and want to tidy up before trying another configuration and build, there are three clean-type targets:
$ make help ... Cleaning targets: clean - Remove most generated files but keep the config and enough build support to build external modules mrproper - Remove all generated files + config + various backup files distclean - mrproper + remove editor backup and patch files
That last one,
distclean, removes every vestige of any previous configuration or build and should take you back to, literally, the pristine, distribution version of the kernel source. That includes even removing your
.config file so don't use that target unless you're serious about cleaning your source tree.
Until now, all of your configuration and compilation has been done in the same directory as the kernel source itself, which is fine for most people but, in some cases, it's more convenient to preserve the kernel source untouched and have all the configuration output and compilation results generated in a remote directory. No problem.
From the top of the kernel source tree, you can do something resembling the following:
$ mkdir ../build_dir $ make O=../build_dir menuconfig $ make O=../build_dir $ sudo make O=../build_dir modules_install
and so on, and so on. And what's the benefit?
For one thing, it leaves the source unpolluted by all of those output files, which makes it easier if you want to search the tree using something like
For another, it allows you to work with a directory of kernel source for which you have no write access. Perhaps it's a system directory, or in some other user's home directory. As long as you can
cd to the top of the source tree and have read access to all of the source, you can generate all of the output elsewhere.
And, finally, this feature lets you work with multiple configurations and builds simultaneously, since you can simply switch from one output directory to another on the fly, using the same kernel source directory as the basis for all of those builds.
There is only one caution, though. Once you initially select an output directory, you must specify that output directory on every subsequent
make invocation, but that should simply be obvious. In fact, the last time I checked, you can't use the remote directory feature if your kernel source tree already shows signs of internal configuration. In short, this feature is meant to be used with a pristine kernel source tree.
Recall from the first lesson that, if you plan on building and installing your own kernels, you should take care that the version strings that they are stamped and installed with don't clash so that they you end up overwriting an earlier kernel that you wanted to keep. You can display the kernel release string of the running kernel with
$ uname -r 2.6.35-crash+ $
And you might remember that you can modify that "extra version" information by simply editing the content at the top of the kernel Makefile before starting a new configuration:
VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 35 EXTRAVERSION = -crash <-- change that part
In fact, there's considerably more to it than that so I'll simply point you at how the configuration and build process generates the release number that will be assigned to the new kernel.
First, there's this incomprehensible excerpt from the Makefile:
# Build the kernel release string # # The KERNELRELEASE value built here is stored in the file # include/config/kernel.release, and is used when executing several # make targets, such as "make install" or "make modules_install." # # The eventual kernel release string consists of the following fields, # shown in a hierarchical format to show how smaller parts are concatenated # to form the larger and final value, with values coming from places like # the Makefile, kernel config options, make command line options and/or # SCM tag information. # # $(KERNELVERSION) # $(VERSION) eg, 2 # $(PATCHLEVEL) eg, 6 # $(SUBLEVEL) eg, 18 # $(EXTRAVERSION) eg, -rc6 # $(localver-full) # $(localver) # localversion* (files without backups, containing '~') # $(CONFIG_LOCALVERSION) (from kernel config setting) # $(LOCALVERSION) (from make command line, if provided) # $(localver-extra) # $(scm-identifier) (unique SCM tag, if one exists) # ./scripts/setlocalversion (only with CONFIG_LOCALVERSION_AUTO) # .scmversion (only with CONFIG_LOCALVERSION_AUTO) # + (only without CONFIG_LOCALVERSION_AUTO # and without LOCALVERSION= and # repository is at non-tagged commit) # # For kernels without CONFIG_LOCALVERSION_AUTO compiled from an SCM that has # been revised beyond a tagged commit, `+' is appended to the version string # when not overridden by using "make LOCALVERSION=". This indicates that the # kernel is not a vanilla release version and has been modified.
And if that's not confusing enough, I recommend perusing the code in the utility script
scripts/setlocalversion to see how even more can be tacked onto the release string that will be used for your new kernel.
However, to make a long story short, if you want to see what release string will be used:
$ make kernelrelease 2.6.35-crash+ $
at which point you can decide if you need to do any adjustment to avoid release string conflicts.
While the final topic for this lesson is somewhat beyond the scope of the course, it's worth seeing at least briefly how you would configure your kernel for building on another architecture.
Take a look at the currently-supported architectures:
$ ls arch alpha blackfin h8300 m32r microblaze parisc score um arm cris ia64 m68k mips powerpc sh x86 avr32 frv Kconfig m68knommu mn10300 s390 sparc xtensa $
and peruse what the configuration process would look like with, for example:
$ make ARCH=blackfin menuconfig
You won't be able to actually build a kernel for any other architecture until you install the appropriate cross-compiler toolchain -- a topic we might very well return to in a future lesson.
We're almost done with establishing the fundamentals we need to start some kernel programming. The last supporting topic we need to cover is the manipulation and examination of loadable kernel modules, which is the topic for the next lesson. And once that's done, starting with lesson four, we'll jump right into writing, compiling and loading our first kernel modules.
And you won't want to miss that.