web-dev-qa-db-ja.com

Linuxカーネルモジュールにローカルヘッダーファイルを含める方法

次のようなソースファイルを含むモジュールmymodがあるとします。

src/mod/mymod.c
src/inc/mymod.h

次のようにmymod.hを含めようとします

_#include <mymod.h>
_

私のメイクファイルにはEXTRA_CFLAGS= -I$(Shell pwd)/../inc/が含まれていますが、カーネルが作成されると、次のエラーが表示されます。

mymod.hが見つかりません

その理由は、カーネルモジュールが作成されると、このコマンドがmakefileから実行されるためです(make V1を使用):

_make -C <path/to/linux/src> M=<path/to/mymod> modules
_

他の作品では、私の$(Shell pwd)が_<path/to/linux>_に拡張されました。これは私が望むものではありません。 mymodソースツリーの_-I_を指すように_src/inc_パラメータを指定するにはどうすればよいですか?

17
Om Narasimhan

LinuxカーネルmakefileはKbuildフレームワークを使用します。これらはGNU makeによって解釈されますが、Kbuildは独特の使用規則を持つ多数のマクロのセットで構成されているため、典型的なmakefileガイドラインは適用されません。タスクの複雑さを考慮します。

Kbuildはカーネルソースの _Documentation/kbuild_ に記載されています。モジュールの作成者は、特に _modules.txt_ を読む必要があります(少なくとも他のユーザーに目を通す必要があります)。

_EXTRA_CFLAGS_変数を使用すると$(Shell pwd)が展開されるため、現在実行していることが機能しません。 makefileはモジュールのディレクトリ(これはKbuildの多くの非自明な側面の1つです)ではなく、カーネルソースツリーから実行されるため、間違ったディレクトリを取得しています。

ツリー外モジュールのインクルードディレクトリを指定する公式のイディオムは_modules.txt_の5.3にあります。 src変数は、モジュールのトップレベルディレクトリに設定されます。したがって:

_EXTRA_CFLAGS := -I$(src)/src/inc
_

この宣言は、モジュールツリーのルートにあるKbuildというファイルにある必要があります。 (srcディレクトリをモジュールツリーのルートと見なすこともできます。その場合は、そこにKbuildを置き、上記の値を-I$(src)/incに置き換えます)。それらをMakefileに入れることも可能ですが、この定義は(カーネルモジュールの構築時にのみ適用されるものであれば)条件付きディレクティブifeq ($(KERNELRELEASE),)内にある必要があります。 _modules.txt_の§4.1を参照してください。

Kbuildファイルをまだ持っておらず、そのファイルに切り替えたい場合は、_modules.txt_の§4.1をお読みください。個別のKbuildファイルを用意する方が少しわかりやすくなります。 make -C $(KERNELDIR) M=$(pwd)を呼び出すルール以外に、カーネルに適用されるものをメインのmakefileに記述しないでください。 Kbuildでは、最低限必要なのは、構築するモジュールのリスト(多くの場合は1つだけ)と、モジュールに含めるファイルのリスト、および依存関係の宣言です。

_EXTRA_CFLAGS := -I$(src)/inc
obj-m := mymod.o
mymod-y := $(src)/mod/mymod.o
$(src)/mod/mymod.o: $(src)/inc/mymod.h
_

従来、現在のソースコードのディレクトリからの相対パスを持つ#includeファイルへの方法は、山括弧ではなく引用符を使用することです。

#include <stdio.h>
#include "mygreatfunctions.h"

この場合、最初の#includeはコンパイラのインクルード検索パス(gccの場合は-Iコマンドラインスイッチによって制御されます)を参照しますが、2つ目は次のディレクトリを調べます#includeのソースファイルが含まれています。

そのようなパスも相対的である可能性があります。したがって、src/mod/mymod.cでは、次のように言うことができます。

#include "../inc/mymod.h"

そして、それは「うまくいく」はずです。

これがLinuxカーネルツリーで一般的な方法であるかどうかはわかりませんが、インクルードパスをいじくり回すよりはましですが、意図しない副作用がいくつか発生する可能性があります。

1
a CVn