2

我有一个足够大的项目,可以从按目录分类文件中受益。我正在尝试用它们构建一个内核模块。

文档指出以下内容:

--- 3.6 Descending down in directories

A Makefile is only responsible for building objects in its own
directory. Files in subdirectories should be taken care of by
Makefiles in these subdirs. The build system will automatically
invoke make recursively in subdirectories, provided you let it know of
them.

To do so, obj-y and obj-m are used.
ext2 lives in a separate directory, and the Makefile present in fs/
tells kbuild to descend down using the following assignment.

Example:
    #fs/Makefile
    obj-$(CONFIG_EXT2_FS) += ext2/

If CONFIG_EXT2_FS is set to either 'y' (built-in) or 'm' (modular)
the corresponding obj- variable will be set, and kbuild will descend
down in the ext2 directory.

但是,这似乎与我需要的不同。由此产生的是两个独立的.ko文件;每个目录中的一个,每个目录中的目标文件的合并。

这是我的项目(简化):

root directory
 |
 +--- Makefile
 |
 +--- foo.c
 |
 +--- subdir
       |
       +--- Makefile
       |
       +--- bar.c

我认为以这样的方式结束是合理的:

root directory
 |
 +--- Makefile
 |
 +--- foo.c
 |
 +--- foo.o (containing foo.c's stuff)
 |
 +--- subdir
 |     |
 |     +--- Makefile
 |     |
 |     +--- bar.c
 |     |
 |     +--- bar.o (containing bar.c's stuff)
 |
 +--- kernel-module.ko (containing foo.o and subdir/bar.o)

我真正结束的是:

root directory
 |
 +--- Makefile
 |
 +--- foo.c
 |
 +--- foo.o (containing foo.c's stuff)
 |
 +--- subdir
 |     |
 |     +--- Makefile
 |     |
 |     +--- bar.c
 |     |
 |     +--- bar.o (containing bar.c's stuff)
 |     |
 |     +--- bar.ko (containing bar.o)
 |
 +--- kernel-module.ko (containing only foo.o)

我希望每个目录构建一个模块不是 Kbuild 设计的基本假设。运送几个模块听起来像是一团糟,没有任何收获。

这是我的根Makefile

KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build

obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o

all:
    make -C ${KERNEL_DIR} M=$$PWD
modules:
    make -C ${KERNEL_DIR} M=$$PWD $@
clean:
    make -C ${KERNEL_DIR} M=$$PWD $@

这是subdir/Makefile

obj-m += bar.o

这是foo.c

int external_function(void);

int test(void)
{
    return external_function();
}

这是subdir/bar.c

int external_function(void)
{
    return 4;
}

make(在根目录中)吐出以下警告:

WARNING: "external_function" [(...)/kernel-module.ko] undefined!

我的插入尝试kernel-module.ko被拒绝:

$ sudo insmod kernel-module.ko
insmod: ERROR: could not insert module kernel-module.ko: Unknown symbol in module
$ dmesg | tail -1
[11688.540153] kernel_module: Unknown symbol external_function (err 0)

我如何告诉 Kbuild 它subdir/bar.o应该是它自己模块的一部分kernel-module.ko而不是它自己的模块?

4

1 回答 1

1

一种解决方案是将 bar 的目标文件附加到内核模块的目标列表中。这段代码的问题:

obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o

是它告诉 Kbuild 下降到subdir/,但它没有告诉它将结果包含在kernel-module.

这将解决:

obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o subdir/bar.o

但是,我根本不喜欢这个解决方案,因为它违反了DRY原则:这意味着bar.o必须命名两次;一进/Makefile一进/subdir/Makefile

此外,此解决方案不会阻止 Kbuild 创建冗余subdir/bar.ko模块。

最后,某些文档指出,由于某些完全未说明的原因,这是“不推荐的做法”。

所以这个解决方案非常糟糕。我不认为我会坚持下去。


另一个解决方案(从前一个分支)是只删除subdir/Makefile,并且在根 Makefile 中,而不是这个:

obj-m += kernel-module.o
obj-m += subdir/
kernel-module-objs += foo.o

做这个:

obj-m += kernel-module.o
kernel-module-objs += foo.o subdir/bar.o

这解决了 DRY 问题并防止subdir/bar.ko生成,但仍然受到不鼓励实践的影响。

在此期间我会坚持这个解决方案,但由于它们都不是理想的,我想我会暂时搁置这个问题。

于 2017-06-02T16:18:57.687 回答