Lesson 2: Further issues in kernel configuration.

Printer-friendly versionPrinter-friendly version

Kernel configuration and building -- the recap

Recall that, during the course of your very first lesson, you managed to:

  • Download a kernel source tree (in our case using git),
  • Configure it appropriately for your system,
  • Build both the main kernel image and all of the selected loadable modules, and
  • Completely install said kernel and modules to the point where you could reboot and come up under your new kernel.

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:

  • Copy at least the new vmlinuz-* compressed kernel image and a corresponding initrd-* initial ramdisk image into the /boot directory,
  • Copy all of the compiled modules into a new kernel-specific directory under /lib/modules, and
  • Update that distribution's GRUB configuration file to add at least one more stanza for the new kernel so that it's selectable at boot time.

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.)

So what's to configure?

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.

make targets 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.

Building verbosely

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

Cleaning up your mess before starting over

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.

Building in an alternate directory

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 grep.

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.

Generating unique build version numbers

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

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:

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.
#         $(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

at which point you can decide if you need to do any adjustment to avoid release string conflicts.

Configuring for another architecture

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.

So ... where to from here?

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.


Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <p> <br> <pre> <h1> <h2> <h3> <h4>
  • Lines and paragraphs break automatically.

More information about formatting options

By submitting this form, you accept the Mollom privacy policy.