我正在编译 Linux 内核模块,但出现以下错误
error: target file "./scripts/target.json" does not exist
make[3]: *** [scripts/Makefile.build:292: /home/guilherme/repositories/rust_learn/hello_world_lkm/hello_world.o] Error 1
make[2]: *** [/home/guilherme/repositories/linux/Makefile:1913: /home/guilherme/repositories/rust_learn/hello_world_lkm] Error 2
make[1]: *** [Makefile:234: __sub-make] Error 2
make[1]: Saindo do diretório '/home/guilherme/repositories/linux'
该模块是一个 Rust 模块,我这样做是为了学习目的。我对 Rust 了解不多,但我研究了这个。我在 C 语言的 Linux 内核模块方面有过短暂的经验,我从 Rust 开始。
我的电脑中安装了 Rust:
$ rustc --version
rustc 1.73.0 (cc66ad468 2023-10-03)
并且我安装了
cargo
:
$ cargo --version
cargo 1.73.0 (9c4383fb5 2023-08-26)
我正在开发的模块非常简单:
use kernel::prelude::*
module! {
type: HelloWorld,
name: b"HelloWorld",
license b"GPL"
};
struct HelloWorld;
impl kernel::Module for HelloWorld {
fn init(_name: &'static CStr, _module: &'static ThisModule) -> Result<Self> {
pr_info!("Hello world");
Ok(HelloWorld)
}
}
impl Drop for HelloWorld {
fn drop(&mut self) {
pr_info!("Adeus mundo cruel fdp");
}
}
我的 Makefile 也很简单:
PWD := $(shell pwd)
obj-m += hello_world.o
CLANG ?= clang
ifeq ($(origin CC),default)
CC := ${CLANG}
endif
all:
$(MAKE) -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) CC=$(CC) CONFIG_CC_IS_CLANG=y modules
clean:
$(MAKE) -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
我安装了
clang
:
$ clang --version
clang version 16.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Rust 在我的内核源代码中可用:
$ make LLVM=1 rustavailable
Rust is available!
我不确定您是否使用安装了 kernel-devel 包的分布式内核来编译树外 rust 模块,但我也遇到了同样的错误。 这里有一些信息可能对您有用。
linux发行版对rust的支持不是很好,所以kernel-devel包总是删除一些重要的文件。
如:
ubuntu 24.04 /usr/src/'uname -r/rust 目录为空。
opensuse tumbleweed /usr/src/'uname -r'/scripts/target.json 丢失
事实上,缺少 ./scripts/target.json 意味着 /usr/src/'uname -r'/scripts/target.json 丢失。
make LLVM=1 V=1 可以提供更多详细信息,可以查看 rustc --target=./scripts/target.json。
在内核编译中,target.json应该使用scripts/generate_rust_target.rs生成,但是发行版不支持这一点,可能是他们的包脚本还不支持rust。
使 LLVM=1 rustavailable 表示当前内核构建工具链已准备就绪,而不是 rust kernel-devel env 已准备就绪(在 tumbleweed 中,即使内核中的 rust 目录丢失,rustavailable 仍然为 true)。
所以,如果你想编译一个out-of-tree rust模块,你仍然需要自己编译一个内核,并将Makefile KDIR更改为你的linux源路径。
但是即使你编译了自己的内核,还有其他问题等待。
模块编译使用 rustc --target=./scripts/target.json,因此目标不正确。
例如,rustc --target=x86_64_unknown.json 表示 rustc 正在搜索名为 x86_64_unknown 的目标,目标配置写入 json 文件中。内容如下
rustc -Z unstable-options --target=x86_64-unknown-linux-gnu --print target-spec-json
并且树外模块构建需要目标的无标准 libcore
target
(target.json)。
我不确定自编译的内核是否可以成功构建libcore,但对我来说, cd
rustc --print sysroot
/lib/rustlib/src/rust/library/core 并执行
cargo build -Z build-std=core --target */scripts/target.json
失败了。
所以,到目前为止,树外模块支持对于 Linux 源代码和 Linux 发行版来说还不是很好。