构建外部模块的命令是:(The command to build an external module is:)
$ make -C <path_to_kernel_src> M=$PWD
由于命令中给出的“M=<dir>”选项,kbuild 系统知道正在构建外部模块。(The kbuild system knows that an external module is being built due to the “M=<dir>” option given in the command.)
要针对正在运行的内核进行构建,请使用:(To build against the running kernel use)
$ make -C /lib/modules/`uname -r`/build M=$PWD
$KDIR 是指内核源目录的路径。($KDIR refers to the path of the kernel source directory.)
make -C $KDIR M=$PWD
在构建外部模块时,只有一部分“make”目标可用。(When building an external module, only a subset of the “make” targets are available.)
make -C $KDIR M=$PWD [target]
all:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
标准的 make -C 指令是这样的:
make -C $KDIR M=$PWD [target],下面分别介绍每个字段的含义。
-C 选项:make -C 表示进入到-C 参数对应的目录中进行编译工作,对应的也是解析目标目录下的
Makefile,编译完成时返回。
$KDIR:/lib/modules/$(shell uname -r)/build/,指定内核源码的位置,表示进行内核源码根目录下
进行编译。
直接在目标板上编译时,内核头文件默认存放在/lib/modules/$(shell uname -r)/build/中,这个
build/目录是一个软连接,链接到源码头文件的安装位置。而内核真正的源码库则直接引用正在运行的内核镜
像。当跨平台编译时,就需要指定相应的内核源码目录,而不是系统中的源码目录,同时交叉编译时,需要指定架构平台和交叉编译工具链;
M=$(PWD):表示在内核中需要被编译的目录,在示例中也就是当前目录。
modules,属于[target]部分,事实上,这是个可选选项。默认行为是将源文件编译并生成内核模块,即
module(s),但是它还支持一下选项:
modules_install:安装这个外部模块,默认安装地址是/lib/modules/$(uname -r)/extra/,同时可以
由内建变量 INSTALL_MOD_PATH 指定安装目录
clean:卸载源文件目录下编译过程生成的文件,在上文的 Makefile 最后一行可以看到。
help:帮助信息
make -C $KDIR M=$PWD bar.lst
make -C $KDIR M=$PWD baz.o
make -C $KDIR M=$PWD foo.ko
make -C $KDIR M=$PWD ./
obj-m := <module_name>.o
kbuild 系统将从 <module_name>.c 构建 <module_name>.o,并在链接后生成内核模块 <module_name>.ko。上面的行可以放在“Kbuild”文件或“Makefile”中。当模块是从多个源构建的时,需要额外的一行来列出文件:(The kbuild system will build <module_name>.o from <module_name>.c, and, after linking, will result in the kernel module <module_name>.ko. The above line can be put in either a “Kbuild” file or a “Makefile.” When the module is built from multiple sources, an additional line is needed listing the files:)
<module_name>-y := <src1>.o <src2>.o ......
hello_world 总是简单的,但是在实际开发中,就会出现更复杂的情况,这时候就需要了解更多的Makefile选项:
首先,当一个 .o 目标文件的生成依赖多个源文件时,显然 make 的自动推导规则就力不从心了(它只能根据同名推导,比如编译 filename.o,只会去查找 filename.c ),我们可以这样指定:
obj-m += hello.o
hello-y := a.o b.o hello_world.o
hello.o 目标文件依赖于 a.o, b.o, hello_world.o,那么这里的 a.o 和 b.o 如果没有指定源文件,根据推导规则就是依赖源文件 a.c, b.c, hello_world.c.
除了hello-y,同时也可以用hello-objs,实现效果是一样的。
同时编译多个可加载模块
kbuild支持同时编译多个可加载模块,也就是生成多个.ko文件,它的格式是这样的:
obj-m := foo.o bar.o
foo-y := <foo_srcs>
bar-y := <bar_srcs>
当编译的目标模块依赖多个头文件时,kbuild对头文件的放置有这样的规定:
直接放置在 Makefile 同在的目录下,在编译时当前目录会被添加到头文件搜索目录。 放置在系统目录,这个系统目录是源代码目录中的 include/linux/,注意是源代码目录而不是系统目录。 与通用的 Makefile 一样,使用 -I$(DIR) 来指定,不同的是,代表编译选项的变量是固定的,为 ccflag,因为当前 Makefile 相当于是镶嵌到 Kbuild 系统中进行编译,所以必须遵循 Kbuild 中的规定.
一般的用法是这样的:
.
|__ src
| |__ complex_main.c
| |__ hal
| |__ hardwareif.c
| |__ include
| |__ hardwareif.h
|__ include
|__ complex.h
--> filename: Kbuild
obj-m := complex.o
complex-y := src/complex_main.o
complex-y += src/hal/hardwareif.o
ccflags-y := -I$(src)/include
ccflags-y += -I$(src)/src/hal/include
ccflags-y := -I$(DIR)/include
kbuild就会将$(DIR)/include目录添加到编译时的头文件搜索目录中。