This article is migrated from Medium and translated by Gemini pro 2.5.
Building modules is heavily related to compiling the kernel, so I took a detour to figure out the kernel compilation process first. My target is a Raspberry Pi 4, the OS is RPi OS 64bit Lite, and my build environment is WSL in Windows.
First, here is the reference I used, the official Raspberry Pi kernel compilation guide:
https://www.raspberrypi.com/documentation/computers/linux_kernel.html
You’ll need to change the command parameters based on your target. The following parameters are all based on my target, so read with caution.
1
| sudo apt install git bc bison flex libssl-dev make libc6-dev libncurses5-dev
|
1
| sudo apt install crossbuild-essential-arm64
|
3. Download the Kernel Source
1
| git clone --depth=1 https://github.com/raspberrypi/linux
|
4. Set Up the Kernel Configuration
1
2
3
4
5
| cd linux
# default config
KERNEL=kernel8
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig
|
You can also use menuconfig to edit the settings:
1
2
| # use menuconfig to config
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
|
Or you can edit the config file directly:
1
2
| # edit file directly
vim .config
|
It’s recommended to modify the General Setup -> Local Version item. This makes it easy to confirm if the kernel has been updated after installation.
5. Start Compiling
1
| make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) Image modules dtbs
|
If you compile directly on the Pi, you don’t have to deal with cross-platform issues, but the compile time is about 2-3 hours. Using WSL, it took me about 30 minutes.
That’s the build process. If it finishes without any errors, it’s successful. Next is deploying the cross-compiled kernel to the Pi.
1. Transfer the Image File
1
| scp arch/arm64/boot/Image <user>@raspberrypi.local:~/tmp
|
2. Transfer the Device Tree Files
1
| scp arch/arm64/boot/dts <user>@raspberrypi.local:~/tmp
|
3. Install Modules Locally (in WSL), Compress, and Transfer
1
2
3
4
5
6
7
8
9
| # install to local wsl
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc) INSTALL_MOD_PATH=../modules modules_install
# compress the folder
cd ..
tar jcvf modules.tar.bz2 modules/
# send to the rpi
scp modules.tar.bz2 <user>@raspberrypi.local:~/tmp
|
After all files are on the Pi, start deploying them. The following operations are on the Raspberry Pi, so SSH in first.
4. Connect to the Raspberry Pi
1
| ssh <user>@raspbberrypi.local
|
5. Deploy the Image
1
| sudo cp tmp/Imgae /boot/firmware/<img_name.img>
|
You can either overwrite the default img file or give it a new name. If you use a new name, you must edit /boot/firmware/config.txt and add a new line kernel=<img_name.img> to specify the boot kernel file.
6. Deploy the Device Tree
1
2
3
| sudo cp tmp/dts/broadcom/*.dtb /boot/firmware/
sudo cp tmp/dts/overlays/*.dtb* /boot/firmware/overlays/
sudo cp tmp/dts/overlays/README /boot/firmware/overlays/
|
7. Deploy the Modules
1
2
3
4
5
6
7
| # decompress
cd tmp
tar jxf modules.tar.bz2
# deploy files
sudo cp -r modules/lib/modules/* /lib/modules/
sudo cp -r modules/lib/firmware/* /lib/firmware/
|
8. Reboot and Verify
1
2
3
4
5
6
7
| sudo reboot
# wait rpi boot then connect
ssh <user>@raspberrypi.local
# check the kernel
uname -r
|
After successfully following these steps, cross-compiling a module is just following the same pattern.
Setting Up the Pi for Native Module Compilation
To enable the Pi to compile modules natively against this custom kernel, we still need to prepare the required files. If you followed the steps above, you’ll notice that /lib/modules/<kernel>/build on the Pi is empty (or a broken symlink). This is because it was a symlink to the build directory on the remote build system (WSL).
1. Clean the Build, Package, and Transfer
1
2
3
4
5
6
7
8
9
| # clear or it will be too large
make mrproper
# compress
cd ..
tar zcvf linux.tar.gz linux/
# send to the rpi
scp linux.tar.gz <user>@raspberrypi.local:~/folder/you/want/to/put
|
1
2
3
4
5
6
7
| # decompress
tar zxvf linux.tar.gz
cd linux
# make modules
make -j$(nproc) prepare
make -j$(nproc) modules_prepare
|
3. Move to the Correct Location and Create the Symlink
1
2
3
4
5
6
| cd ..
mv linux/ <header_name>/
sudo mv <header_name> /usr/src/
sudo rm /lib/modules/<kernel>/build
sudo ln -s /usr/src/<header_name> /lib/modules/<kernel>/build
|
And with that, you can now compile modules natively on the Raspberry Pi.