Linux カーネルモジュールの Makefile をカーネルツリー内外兼用にする


はじめに
------------------------------------------------------------------------------------

### この記事の目的

Linux のカーネルモジュールを Linux のカーネルツリー内に追加してビルドする際の Makefile の書き方と
カーネルツリーの外からビルドする際の Makefile の書き方は微妙に違っています。
Makefile をカーネルツリー内用とカーネルツリー外用と個別に用意するのもなんだか面倒です。
そこでこの記事では Linux カーネルモジュールの Makefile をカーネルツリー内外兼用にする方法について説明します。

既存の Makefile の説明
------------------------------------------------------------------------------------

まず、この節で、カーネルツリー内に追加してビルドする際の Makefile と カーネルツリーの外からビルドする際の Makefile の特徴について簡単に説明します。

### カーネルツリー内に追加してビルドする際の Makefile と Kconfig

Linux のカーネルツリーにすでに組み込まれているカーネルモジュールの Makefile はだいたい次のようになっています。

```Makefile:$(KERNEL_SRC)/drivers/staging/sample/Makefile
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_SAMPLE)	+= sample.o
```

上の Makefile で参照されている CONFIG_SAMPLE は Makefile と同じディレクトリにある Kconfig で次のように定義されているとします。

```Kconfig:$(KERNEL_SRC)/drivers/staging/sample/Kconfig
# SPDX-License-Identifier: GPL-2.0-only
menuconfig SAMPLE
	tristate "This is Sample Kernel Module"
	help
	  Enable this to allow the sample kernel module to be built.
	  If you don't know what to do here, say N.
```

上記の Makefile と Kconfig を次のようにして上位のディレクトリ(この例では ```drivers/staging/```) にある Makefile と Kconfig に追加しておきます。

```Makefile:$(KERNEL_SRC)/drivers/staging/Makefile
#    :
#    (前略)
#    :
obj-$(CONFIG_SAMPLE)	+= sample/
```

```Kconfig:$(KERNEL_SRC)/drivers/staging/Kconfig
#    :
#    (前略)
#    :
source "drivers/staging/sample/Kconfig"
```

こうしておけば、Linux Kernel のビルド時に make menuconfig でメニューの Staging drivers に SAMPLE の項目が追加されるので ```m``` や ```y``` を指定することができるようになります。
また、直接 defconfig ファイルに ```CONFIG_SAMPLE=m``` や ```CONFIG_SAMPLE=m``` を書いておいてもいいでしょう。

### カーネルツリー外でビルドする際の Makefile

Linux のカーネルモジュールをカーネルのソースの外でビルドする際、たいてい次のような Makefile を使います。

```Makefile:Makefile
#
# For in kernel tree variables
# 
obj-m := sample.o

#
# For out of kernel tree variables
#
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build

#
# For out of kernel tree rules
#
all:
	$(MAKE) -C $(KERNEL_SRC) M=$(PWD)

clean:
	$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean

```

この Makefile の説明は、前回の記事[『Linux カーネルモジュールの Makefile は二度呼ばれる』@Qiita](https://qiita.com/ikwzm/items/0a1141eb597cd59549a9) を参照してください。
余段ですが、もともと前回の記事は今回の記事の一部だったのですが、ちょっと記事の量が多かったので別々にした経緯があります。

Makefile をカーネルツリー内外兼用にする
------------------------------------------------------------------------------------

まず、カーネルツリー外でビルドする際の Makefile の 変数 ```obj-m``` の名前を ```obj-$(CONFIG_SAMPLE)``` に変更します。(さらに 代入演算子を ```:=``` から ```+=``` に変更します。)
こうすることで、この Makefile をカーネルツリー内に直接置いて、Kconfig と連動することができるようになります。

ただし、変数 ```obj-m``` の名前を ```obj-$(CONFIG_SAMPLE)``` に変更しただけでは、今度はカーネルツリー外でビルドすることが出来ません。
何故なら、前回の記事[『Linux カーネルモジュールの Makefile は二度呼ばれる』@Qiita](https://qiita.com/ikwzm/items/0a1141eb597cd59549a9)で説明したようにこの Makefile は二度読まれるのですが、```CONFIG_SAMPLE``` が定義されていないので、二度目に Makefile の読み込まれた際に ```obj- += sample.o``` と解釈されてしまい、ビルド対象から外れるからです。

そこで ```make -C $(KERNEL_SRC) M=$(PWD)``` を実行する際の文に ```CONFIG_SAMPLE=m``` を追加しておきます。
こうすることで、二度目に Makefile の読み込まれた際に ```obj-m += sample.o``` と解釈され、カーネルモジュールとしてビルドされます。

```Makefile:Makefile
#
# For in kernel tree variables
# 
obj-$(CONFIG_SAMPLE) += sample.o

#
# For out of kernel tree variables
#
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build

#
# For out of kernel tree rules
#
all:
	$(MAKE) -C $(KERNEL_SRC) M=$(PWD) CONFIG_SAMPLE=m

modules_install:
	$(MAKE) -C $(KERNEL_SRC) M=$(PWD) CONFIG_SAMPLE=m modules_install

clean:
	$(MAKE) -C $(KERNEL_SRC) M=$(PWD) CONFIG_SAMPLE=m clean

```

さらに Makefile を Yocto に対応する？
------------------------------------------------------------------------------------

あと、これは未確認ですが、Yocto (Petalinux) でカーネルモジュールをビルドする際には、カーネルソースのディレクトリが変数
 ```KERNEL_SRC``` に設定されているようです。
 したがって、```make -C ``` で指定するカーネルソースのパスに ```$(KERNEL_SRC)``` を参照するようにしておけば Yocto (Petalinux) でも、この Makefile が使えるようです。

私は Yocto (Petalinux) を使っていないので分からないですが、udmabuf の issue によると、どうやらいけるようです。

  * [『PetaLinux 2023.1 / Yocto Langdale build - no .ko files are installed, thus no package is created』 udmabuf issue #106](https://github.com/ikwzm/udmabuf/issues/106)

余談ですが、もともとこの記事を書こうと思ったのは、上の issue に触発されて、udmabuf の Makefile を見直したためでした。おかげさまで Linux カーネルモジュールの Makefile について少し理解が深まりました。issue をくれた方には感謝です。

参考
------------------------------------------------------------------------------------

  * [『Linux カーネルモジュールの Makefile は二度呼ばれる』@Qiita](https://qiita.com/ikwzm/items/0a1141eb597cd59549a9)
  * [『PetaLinux 2023.1 / Yocto Langdale build - no .ko files are installed, thus no package is created』 udmabuf issue #106](https://github.com/ikwzm/udmabuf/issues/106)