In this lesson, you will learn how to prepare your development workstation to cross-compile custom loadable kernel modules (LKMs) for your target embedded hardware.
When developing kernel modules, you cannot simply compile them against your host machine’s headers; the module must be built against the specific kernel source version and configuration running on your target device. To achieve this, you need a matching cross-compilation toolchain and the "prepared" kernel build tree.
Setting Up the Environment
First, ensure your CROSS_COMPILE environment variable points to the prefix of your toolchain (e.g., arm-linux-gnueabihf-). Next, obtain the kernel source that exactly matches the version running on your target hardware.
To prepare the build environment, you must perform a "distclean" and apply the target's configuration:
# Set your target architecture and cross-compiler
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
# Configure the kernel to match the target's running config
# Often retrieved from /proc/config.gz on the target
make mrproper
make defconfig # or use your .config file
make modules_prepare
The make modules_prepare command is the secret sauce here. It generates the necessary header files and symbol maps required to compile external modules without needing to perform a full, time-consuming kernel build.
Building Your Module
Once prepared, your Makefile for the external module must point to this kernel tree:
obj-m += my_driver.o
KDIR := /path/to/your/kernel/source
all:
make -C $(KDIR) M=$(PWD) modules
When you run make, the build system uses the configuration flags and internal headers from KDIR to ensure your module's memory layout and function signatures match the target kernel exactly. If these do not align—specifically the vermagic string—the kernel will refuse to load your module, resulting in a "Invalid module format" error. By keeping your environment synchronized, you ensure that your drivers interact safely with the kernel’s subsystem interfaces.
Key Takeaway: To successfully compile loadable kernel modules, you must build them against a kernel source tree configured identically to your target's runtime kernel, using the modules_prepare target to initialize the necessary build artifacts.