在一个单独的对象目录中构建一个独立于内核的Linux内核模块

10

我正在与Linux内核构建系统(Kbuild,内核≥2.6.28)以及一个更大项目的目录结构和构建系统进行对抗。我们的项目包含一个非内置的Linux内核模块,我们的目录结构看起来像这样(显然是简化过的):

checkout/src/common/*.c           source files (common to Linux and other platforms)
checkout/src/linux-driver/*.c     source files (for the Linux kernel driver)
checkout/build/linux/Kbuild       Kbuild
tmp/linux-2.6.xx/                 where the Linux kernel is unpacked and configured
output/linux-arm-debug/           where object files must end up

构建过程不能修改checkout目录下的任何内容,构建模块不能修改tmp/linux-2.6.xx目录下的任何内容。所有输出文件都必须位于output/linux-arm-debug目录下(或者在构建时选择的其他架构和调试版本)。

我已经阅读了kbuild/modules.txt,并开始编写我的Kbuild文件:

MOD_OUTPUT_DIR = ../../../output/linux-$(ARCH)-$(DEBUG)
obj-m += $(MOD_OUTPUT_DIR)/foo_mod.o
$(MOD_OUTPUT_DIR)/our_module-objs := $(MOD_OUTPUT_DIR)/foo_common.o $(MOD_OUTPUT_DIR)/foo_linux.o

这处理了将对象文件存储在与Kbuild不同的目录中。现在我如何指定foo_common.o需要从…/checkout/src/common/foo_common.c编译,以及foo_linux.o需要从…/checkout/src/linux-driver/foo_linux.c编译?

6个回答

13

这里是一个Makefile,可以为源代码目录外的内核模块进行编译(改编自@Mark的评论)...

KDIR ?= /lib/modules/$(shell uname -r)/build
BUILD_DIR ?= $(PWD)/build
BUILD_DIR_MAKEFILE ?= $(PWD)/build/Makefile

default: $(BUILD_DIR_MAKEFILE)
    make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) modules

$(BUILD_DIR):
    mkdir -p "$@"

$(BUILD_DIR_MAKEFILE): $(BUILD_DIR)
    touch "$@"

clean:
    make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) clean

注意:您仍然需要一个Kbuild文件...

obj-m += my_driver.o

我不明白为什么我们仍然需要一个Kbuild文件 obj-m += my_driver.o - GShaik
这只是个人偏好问题。如果你想的话,可以将这行代码添加到Makefile中。将其放入Kbuild文件中可以通过删除Makefile中用于保护此语句的ifneq ($(KERNELRELEASE),)测试来简化Makefile。参见:http://www.makelinux.net/ldd3/chp-2-sect-4.shtml - Sandeep Datta
这非常接近我所需的内容,但遗憾的是它假定模块 Makefilesrc 目录中,而这对我来说并不是这种情况(它是由 autoconf 构建的,因此 Makefile.in 在源代码中,而 Makefile 在 build/M 目录中,Kbuild 文件也是如此)。 - Miral
1
如果在modules.txt中记录了src=,我会感觉更好 :-( - Ciro Santilli OurBigBook.com
1
是的,我知道这已经过去好几年了,但我觉得“src =”在做什么的问题是很重要的。 - Benjamin Crawford Ctrl-Alt-Tut

3

我遇到了类似的问题。我按照以下方式修改了linux_2_6_34/scripts/Makefile.build文件。

ifdef SRCDIR
src := $(SRCDIR)
else
src := $(obj)
endif

SRCDIR 是源目录。

编译模块的方法是运行

make -c $(KDIR) M=$(Your_output_dir) SRCDIR=$(your source directory)`

快了 - c 文件已编译,但它拒绝迈出生成 .ko(版本 3.14.0)的最后一步。 - Greg
抱歉,我犯了一个错误 - 代码中有个问题 - 我的 Kbuild 文件有个 bug,但是我已经解决了。不过要注意的是,它会在选择目录时有点混乱,并且某个阶段需要在两个目录中都有 Kbuild 文件。为使其正常运行,这只是一个小代价。 - Greg
这似乎是有效的,但出于某种原因,我需要在输出目录中有一个空的Makefile才能使其工作(linux-4.1.6)。 - Kenny Ho
3
我已经让它正常运行了,而没有修改Makefile.build或任何其他文件的内容:make -C /path/to/linux-3.16.1/build M=/path/to/module/build src=/path/to/module.我不知道这是否适用于其他版本的内核,但也许可以尝试一下。我仍然需要在构建目录中运行touch Makefile - Mark
@Mark,关于交叉编译,我能否像上面指定的那样编写Makefile?如果可以,我需要在哪里指定交叉编译器选项。顺便说一下,我想使用arm-eabi-gcc进行交叉编译。 - GShaik
@AbdulGafoor 不确定你所说的 " ...as above specified " 是指什么。Jegan 正在修改内核 makefile。如果你也要这样做,那我所做的没有太多意义。如果你不想修改内核 makefile,请按照第3.2节示例2中的说明创建 MakefileKbuild,网址为 https://www.kernel.org/doc/Documentation/kbuild/modules.txt - 这就是我所做的。然后(如果我没记错的话)在调用 Makefile 上的 make 时指定交叉编译选项,它会将它们传递给 Kbuild。希望这能起作用,但我对交叉编译有点陌生。 - Mark

2

我的不太优美但却有效的解决方案是将源文件复制到输出目录中。

FOO_SOURCES_DIR = $(src)/../../../checkout/src
FOO_MOD_OUTPUT_DIR = ../../../output/linux-$(ARCH)-$(DEBUG)

# Specify the object files
obj-m += $(FOO_MOD_OUTPUT_DIR)/foo_mod.o
FOO_MODULE_OBJS := $(FOO_MOD_OUTPUT_DIR)/foo_common.o $(FOO_MOD_OUTPUT_DIR)/foo_linux.o
$(FOO_MOD_OUTPUT_DIR)/foo_mod-objs := $(FOO_MODULE_OBJS)

# Where to find the sources
$(src)/$(FOO_MOD_OUTPUT_DIR)/foo_common.c: $(FOO_SOURCES_DIR)/common/foo_common.c
$(src)/$(FOO_MOD_OUTPUT_DIR)/foo_linux.c: $(FOO_SOURCES_DIR)/linux-driver/foo_linux.c

# Rules to copy the sources
FOO_COPIED_SOURCES = $(patsubst %.o,$(src)/%.c,$(FOO_MODULE_OBJS))
$(FOO_COPIED_SOURCES):
        $(Q)mkdir -p $(@D)
        cp -f $< $@
clean-files += $(FOO_COPIED_SOURCES)
clean-dirs += $(FOO_MOD_OUTPUT_DIR)

复制?至少创建一次符号链接,然后就不要再动它了! - Shahbaz
2
@Shahbaz 符号链接在构建树中并不总是有效。它们往往作为存档文件中的符号链接被包含。我甚至曾经不得不处理Samba导出(呕吐)。在Linux内核构建树中复制一些源文件非常容易。 - Gilles 'SO- stop being evil'

1

虽然您还没有提到您已经尝试了什么(或者是否已经找到了解决方案),但看起来您只需要继续向下查看modules.txt文件的一点点内容 - 到第4.3节

--- 4.3 Several Subdirectories

kbuild can handle files that are spread over several directories.
Consider the following example:

.
|__ src
|   |__ complex_main.c
|   |__ hal
|   |__ hardwareif.c
|   |__ include
|       |__ hardwareif.h
|__ include
    |__ complex.h

To build the module complex.ko, we then need the following
kbuild file:

    --> 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

As you can see, kbuild knows how to handle object files located
in other directories. The trick is to specify the directory
relative to the kbuild file's location. That being said, this
is NOT recommended practice.

For the header files, kbuild must be explicitly told where to
look. When kbuild executes, the current directory is always the
root of the kernel tree (the argument to "-C") and therefore an
absolute path is needed. $(src) provides the absolute path by
pointing to the directory where the currently executing kbuild
file is located.

4
我已阅读该部分,但对于它如何帮助我感到困惑。 在那个例子中,complex_main.ccomplex_main.o位于同一目录中。在我的构建树中,源代码和构建产品是完全分开的。 - Gilles 'SO- stop being evil'

0
有点晚了,但看起来 O= flag 是你需要的。

看起来没问题。如果我没有尝试过,我会感到惊讶,但已经过了一段时间,我已经转向其他项目,所以我不能确定。谢谢你的建议,我会尽力找机会尝试它。 - Gilles 'SO- stop being evil'
7
对我来说不起作用 - 看起来 O=KBUILD_OUTPUT 都需要应用于构建内核本身的点,而不仅仅是外部模块。 我看到的是在源树中找不到生成的文件的错误 - 例如 linux/version.h - 它正在 O= 位置中寻找它们。 - Greg

-1

您可以设置环境变量KBUILD_OUTPUT。这类似于O=选项的功能;但是,由于它是一个环境变量,它可以跨越多个makefile,而O=无法传递或需要构建一个超出目录的模块。我曾经遇到过同样的问题,尝试构建一组兼容性无线模块,我需要为实际的内核映像构建使用O=


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接