Driver porting: compiling external modules
| This article is part of the LWN Porting Drivers to 2.6 series. |
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. (后面的一偏文章会谈到,2.6的模块的版本识别。这种识别对模块的兼容性要求极高,有gcc版本、SMP与否、强占内核与否、kernel version)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.
The wire control’s high cost forces me to buy a second hand one. I also want to have a iPod’s case, a cool one i found is a Belkin