The 2.5 development series saw extensive changes to the kernel build mechanism and
the complete replacement of the module loading code. One result of these
changes is that compiling loadable modules has gotten a bit more
complicated. In the 2.4 days, a makefile for an external module could be
put together in just about any old way; typically a form like the following
was used:
KERNELDIR = /usr/src/linux
CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O
all: module.o
Real-world makefiles, of course, tended to be a bit more complicated, but
the job of creating a loadable module was handled in a single, simple
compilation step. All you really needed was a handy set of kernel headers
to compile against.
With the 2.6 kernel, you still need those headers. You also, however, need
a configured kernel source tree and a set of makefile rules describing how
modules are built. There's a few reasons for this:
- The new module loader needs to have some extra symbols defined at
compilation time. Among other things, it needs to have the
KBUILD_BASENAME and KBUILD_MODNAME symbols defined.
- All loadable modules now need to go through a linking step - even those
which are built from a single source file. The link brings in
init/vermagic.o from the kernel source tree; this object
creates a special section in the loadable module describing the
environment in which it was built. It includes the compiler version
used, whether the kernel was built for SMP, whether kernel preemption
is enabled, the architecture which was compiled for, and, of course,
the kernel version. A difference in any of these parameters can
render a module incompatible with a given running kernel; rather than
fail in mysterious ways, the new module loader opts to detect these
compatibilities and refuse to load the module.
As of this writing (2.5.59), the "vermagic" scheme is fallible in that
it assumes a match between the kernel's vermagic.o file and
the way the module is being built. That will normally be the case,
but people who change compiler versions or perform some sort of
compilation trickery could get burned.
- The new symbol versioning scheme ("modversions") requires a separate
post-compile processing step and yet another linkable object to hold
the symbol checksums.
One could certainly, with some effort, write a new, standalone makefile
which would handle the above issues. But that solution, along with being a
pain, is also brittle; as soon as the module build process changes again,
the makefile will break. Eventually that process will stabilize, but, for
a while, further changes are almost guaranteed.
So, now that you are convinced that you want to use the kernel build system
for external modules, how is that to be done? The first step is to learn
how kernel makefiles work in general; makefiles.txt from a recent kernel's
Documentation/kbuild directory is recommended reading. The
makefile magic needed for a simple kernel module is minimal, however. In
fact, for a single-file module, a single-line makefile will suffice:
obj-m := module.o
(where module is replaced with the actual name of the resulting
module, of course). The kernel build system, on seeing that declaration,
will compile module.o from module.c, link it with
vermagic.o, and leave the result in module.ko, which can
then be loaded into the kernel.
A multi-file module is almost as easy:
obj-m := module.o
module-objs := file1.o file2.o
In this case, file1.c and file2.c will be compiled, then
linked into module.ko.
Of course, all this assumes that you can get the kernel build system to
read and deal with your makefile. The magic command to make that happen is
something like the following:
make -C /path/to/source SUBDIRS=$PWD modules
Where /path/to/source is the path to the source directory for the
(configured and built)
target kernel. This command causes make to head over to the kernel source
to find the top-level makefile; it then moves back to the original
directory to build the module of interest.
Of course, typing that command could get tiresome after a while. A trick
posted by Gerd Knorr can make things a little easier, though. By looking
for a symbol defined by the kernel build process, a makefile can determine
whether it has been read directly, or by way of the kernel build system.
So the following will build a module against the source for the currently
running kernel:
ifneq ($(KERNELRELEASE),)
obj-m := module.o
else
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
Now a simple "make" will suffice. The makefile will be read twice; the
first time it will simply invoke the kernel build system, while the actual
work will get done in the second pass. A makefile written in this way is
simple, and it should be robust with regard to kernel build changes.
Post a comment
|