はじめに
Yoctoのセルフコンパイル環境でout-of-treeのカーネルモジュールをビルドする。
普通にビルドしようとエラーが発生するのでその回避方法をメモしておく。
hello-mod
今回はrecipe-skeleton/recipes-kernelにあるhello-modをラズベリーパイ3上でビルドする。
Yoctoのイメージ
今回使用するセルフコンパイル環境を作成するには、local.confに次の内容を追加する。
# for raspberrypi3
MACHINE = "raspberrypi3"
DL_DIR ?= "${TOPDIR}/../downloads"
# enable uart
ENABLE_UART = "1"
# enable self-compile
EXTRA_IMAGE_FEATURES_append = " dev-pkgs tools-debug tools-sdk"
# add kernel soruce
IMAGE_INSTALL_append = "kernel-devsrc"
カーネルソースを含むパッケージkernel-devsrcを追加する。
作成するモジュール
~/helloにソースとMakefileを作成する。
$ mkdir ~/hello $ cd hello
~/hello/hello.cを次の内容で作成する。
#include <linux/module.h> int init_module(void) { printk("Hello World!\n"); return 0; } void cleanup_module(void) { printk("Goodbye Cruel World!\n"); } MODULE_LICENSE("GPL");
~/hello/Makefileを次の内容で作成する。
obj-m := hello.o
SRC := $(shell pwd)
all:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC)
modules_install:
$(MAKE) -C $(KERNEL_SRC) M=$(SRC) modules_install
clean:
rm -f *.o *~ core .depend .*.cmd *.ko *.mod.c
rm -f Module.markers Module.symvers modules.order
rm -rf .tmp_versions Modules.symvers
このMakefileではKERNEL_SRCを変数にしているので、make実行に次のようにするか
# cd ~/hello # make KERNEL_SRC=/lib/modules/`uname -r`/build
予め環境変数に登録しておく。
# export KERNEL_SRC=/lib/modules/`uname -r`/build # make
発生するエラーの内容
初期状態でモジュールをビルドすると次のようなエラーが発生する。
# make KERNEL_SRC=/lib/modules/`uname -r`/build
make -C /lib/modules/4.14.79/build M=/home/root/hello
make[1]: Entering directory '/lib/modules/4.14.79/build'
make[1]: Warning: File 'scripts/Makefile.ubsan' has modification time 601 s in the future
make[2]: Warning: File 'scripts/Makefile.lib' has modification time 601 s in the future
AR /home/root/hello/built-in.o
CC [M] /home/root/hello/hello.o
In file included from ./include/asm-generic/int-ll64.h:11,
from ./arch/arm/include/uapi/asm/types.h:5,
from ./include/uapi/linux/types.h:5,
from ./include/linux/types.h:6,
from ./include/linux/list.h:5,
from ./include/linux/module.h:9,
from /home/root/hello/hello.c:1:
./include/uapi/asm-generic/int-ll64.h:12:10: fatal error: asm/bitsperlong.h: No such file or directory
#include <asm/bitsperlong.h>
^~~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [scripts/Makefile.build:335: /home/root/hello/hello.o] Error 1
make[1]: *** [Makefile:1527: _module_/home/root/hello] Error 2
make[1]: Leaving directory '/lib/modules/4.14.79/build'
make: *** [Makefile:6: all] Error 2
fatal error: asm/bitsperlong.h: No such file or directory。bitsperlong.hが見つからないというエラーが出る。
エラー回避の方法
まずは、ラズベリーパイの時刻が狂っているので現在時刻に設定する。
$ date -s "MM/DD hh:mm YYYY"
日付を合わせておかないとwarning: Clock skew detected. Your build may be incomplete.という警告が出る。
実害はなさそうだが気持ち悪いので対策しておく。
次にカーネルソースのscriptsをビルドする。
$ cd /lib/modules/`uname -r`/build $ make scripts
bitsperlong.hのエラーはこちらで対策できる。
再びビルド
再度モジュールをビルドしてみる。
# cd ~/hello # make KERNEL_SRC=/lib/modules/`uname -r`/build make -C /lib/modules/4.14.79/build M=/home/root/hello make[1]: Entering directory '/lib/modules/4.14.79/build' AR /home/root/hello/built-in.o CC [M] /home/root/hello/hello.o Building modules, stage 2. MODPOST 1 modules CC /home/root/hello/hello.mod.o LD [M] /home/root/hello/hello.ko make[1]: Leaving directory '/lib/modules/4.14.79/build'
hello.koが生成される。
ほかのヘッダファイルでエラー
たとえば、hello.cの先頭の方にに次の行を追加する。
#include <linux/module.h> #include <linux/unistd.h> ...(snip)...
すると、makeで次のエラーが発生する。
# make KERNEL_SRC=/lib/modules/`uname -r`/build
make -C /lib/modules/4.14.79/build M=/home/root/hello
make[1]: Entering directory '/lib/modules/4.14.79/build'
CC [M] /home/root/hello/hello.o
In file included from ./arch/arm/include/asm/unistd.h:16,
from ./include/uapi/linux/unistd.h:8,
from /home/root/hello/hello.c:2:
./arch/arm/include/uapi/asm/unistd.h:21:10: fatal error: asm/unistd-eabi.h: No such file or directory
#include <asm/unistd-eabi.h>
^~~~~~~~~~~~~~~~~~~
compilation terminated.
make[2]: *** [scripts/Makefile.build:335: /home/root/hello/hello.o] Error 1
make[1]: *** [Makefile:1527: _module_/home/root/hello] Error 2
make[1]: Leaving directory '/lib/modules/4.14.79/build'
make: *** [Makefile:6: all] Error 2
これは次のコマンドで回避できる。
# cd /lib/modules/`uname -r`/build # make prepare
最終的な回避策
Yoctoで作成したセルフコンパイル環境でout-of-treeのカーネルモジュールをビルドするためには、
カーネルソースで予めscriptsとprepareをmakeしておく必要がある。
# cd /lib/modules/`uname -r`/build # make scripts # make prepare
hello.cに次のようなincludeを追加したが、とりあえずのところエラーは発生していない。
#include <linux/module.h> #include <linux/unistd.h> #include <linux/init.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/sched.h> #include <linux/device.h> #include <linux/slab.h> #include <asm/current.h> #include <asm/uaccess.h> #include <asm/io.h> ...(snip)...