Skip to content
This repository was archived by the owner on Mar 7, 2021. It is now read-only.

Commit c02b3f1

Browse files
committed
Fixes #177 -- let the kernel build process drive cargo
1 parent ede0645 commit c02b3f1

File tree

9 files changed

+75
-113
lines changed

9 files changed

+75
-113
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ install:
1717
- rustup component add rust-src rustfmt clippy
1818

1919
script:
20-
- ./tests/run_tests.py
20+
- CC=clang ./tests/run_tests.py
2121
- |
2222
for p in . hello-world tests/*; do
2323
if [ -d "$p" ]; then

README.md

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,8 @@ various other examples in the tests/ directory.
2020
We run [bindgen](https://github.com/rust-lang/rust-bindgen) on the
2121
kernel headers to generate automatic Rust FFI bindings. bindgen is
2222
powered by [Clang](https://clang.llvm.org), so we use use the kernel's
23-
own build system to determine the appropriate CFLAGS (see
24-
`kernel-cflags-finder`) and pass them to bindgen (see `build.rs`). Then we
25-
write safe bindings to these types (see the various files inside `src/`).
23+
own build system to determine the appropriate CFLAGS. Then we write safe
24+
bindings to these types (see the various files inside `src/`).
2625

2726
Each kernel module in Rust lives in a `staticlib` crate, which generates
2827
a `.a` file. We pass this object to the Linux kernel's own module build
@@ -52,12 +51,13 @@ or higher [to bind constants
5251
properly](https://github.com/rust-lang/rust-bindgen/issues/1316). If
5352
you're running kernel 5.0 or newer, [you'll need Clang
5453
9](https://github.com/fishinabarrel/linux-kernel-module-rust/issues/123)
55-
(currently the development release). You may need to set the `CLANG`
56-
environment variable appropriately, e.g., `CLANG=clang-9`.
54+
(currently the development release). You may need to set the `CC`
55+
environment variable appropriately, e.g., `CC=clang-9`.
5756

5857
## Building hello-world
5958

60-
1. Install clang, kernel headers, and the `rust-src` and `rustfmt` components from `rustup`:
59+
1. Install clang, kernel headers, and the `rust-src` and `rustfmt` components
60+
from `rustup`:
6161

6262
```
6363
apt-get install llvm clang linux-headers-"$(uname -r)" # or the equivalent for your OS
@@ -70,19 +70,14 @@ rustup component add --toolchain=nightly rust-src rustfmt
7070
cd hello-world
7171
```
7272

73-
3. Build the static object with cargo build, pointing it at our custom target
74-
75-
```
76-
cargo build -Z build-std=core,alloc --target x86_64-linux-kernel
77-
```
78-
79-
4. Build the kernel module using the Linux kernel build system (kbuild)
73+
3. Build the kernel module using the Linux kernel build system (kbuild), this
74+
will invoke `cargo` to build the Rust code
8075

8176
```
8277
make
8378
```
8479

85-
5. Load and unload the module!
80+
4. Load and unload the module!
8681

8782
```
8883
sudo insmod helloworld.ko

build.rs

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -85,32 +85,56 @@ fn handle_kernel_version_cfg(bindings_path: &PathBuf) {
8585
}
8686
}
8787

88+
// Takes the CFLAGS from the kernel Makefile and changes all the include paths to be absolute
89+
// instead of relative.
90+
fn prepare_cflags(cflags: &str, kernel_dir: &str) -> Vec<String> {
91+
let cflag_parts = shlex::split(&cflags).unwrap();
92+
let mut cflag_iter = cflag_parts.iter();
93+
let mut kernel_args = vec![];
94+
while let Some(arg) = cflag_iter.next() {
95+
if arg.starts_with("-I") && !arg.starts_with("-I/") {
96+
kernel_args.push(format!("-I{}/{}", kernel_dir, &arg[2..]));
97+
} else if arg == "-include" {
98+
kernel_args.push(arg.to_string());
99+
let include_path = cflag_iter.next().unwrap();
100+
if include_path.starts_with("/") {
101+
kernel_args.push(include_path.to_string());
102+
} else {
103+
kernel_args.push(format!("{}/{}", kernel_dir, include_path));
104+
}
105+
} else {
106+
kernel_args.push(arg.to_string());
107+
}
108+
}
109+
return kernel_args;
110+
}
111+
88112
fn main() {
89113
println!("cargo:rerun-if-env-changed=KDIR");
90-
println!("cargo:rerun-if-env-changed=CLANG");
91-
println!("cargo:rerun-if-changed=kernel-cflags-finder/Makefile");
92-
let output = Command::new("make")
93-
.arg("-C")
94-
.arg("kernel-cflags-finder")
95-
.arg("-s")
96-
.output()
97-
.unwrap();
98-
if !output.status.success() {
99-
eprintln!("kernel-cflags-finder did not succeed");
100-
eprintln!("stdout: {}", std::str::from_utf8(&output.stdout).unwrap());
101-
eprintln!("stderr: {}", std::str::from_utf8(&output.stderr).unwrap());
102-
std::process::exit(1);
103-
}
114+
println!("cargo:rerun-if-env-changed=CC");
115+
println!("cargo:rerun-if-env-changed=KERNEL_CLFAGS");
116+
117+
let kernel_cflags = env::var("KERNEL_CLFAGS").expect("Must be invoked from kernel makefile");
118+
let kernel_dir = env::var("KDIR").unwrap_or_else(|_| {
119+
format!(
120+
"/lib/modules/{}/build",
121+
std::str::from_utf8(&(Command::new("uname").arg("-r").output().unwrap().stdout))
122+
.unwrap()
123+
.trim()
124+
)
125+
});
126+
let kernel_args = prepare_cflags(&kernel_cflags, &kernel_dir);
104127

105128
let mut builder = bindgen::Builder::default()
106129
.use_core()
107130
.ctypes_prefix("c_types")
108131
.derive_default(true)
109132
.rustfmt_bindings(true);
110133

134+
// TODO: Support building for other kernel targets!
111135
builder = builder.clang_arg("--target=x86_64-linux-kernel");
112-
for arg in shlex::split(std::str::from_utf8(&output.stdout).unwrap()).unwrap() {
113-
builder = builder.clang_arg(arg.to_string());
136+
for arg in kernel_args.iter() {
137+
builder = builder.clang_arg(arg.clone());
114138
}
115139

116140
println!("cargo:rerun-if-changed=src/bindings_helper.h");
@@ -138,12 +162,11 @@ fn main() {
138162
handle_kernel_version_cfg(&out_path.join("bindings.rs"));
139163

140164
let mut builder = cc::Build::new();
141-
println!("cargo:rerun-if-env-changed=CLANG");
142-
builder.compiler(env::var("CLANG").unwrap_or("clang".to_string()));
165+
builder.compiler(env::var("CC").unwrap_or("clang".to_string()));
143166
builder.target("x86_64-linux-kernel");
144167
builder.warnings(false);
145168
builder.file("src/helpers.c");
146-
for arg in shlex::split(std::str::from_utf8(&output.stdout).unwrap()).unwrap() {
169+
for arg in kernel_args.iter() {
147170
builder.flag(&arg);
148171
}
149172
builder.compile("helpers");

hello-world/Makefile

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1+
ifneq ($(KERNELRELEASE),)
12
obj-m := helloworld.o
23
helloworld-objs := hello_world.rust.o
3-
KDIR ?= /lib/modules/$(shell uname -r)/build
4+
5+
$(src)/target/x86_64-linux-kernel/debug/libhello_world.a: $(src)/Cargo.toml $(wildcard $(src)/src/*.c)
6+
cd $(src); env -u MAKE -u MAKEFLAGS KERNEL_CLFAGS="$(c_flags)" cargo build -Z build-std=core,alloc --target=x86_64-linux-kernel
47

58
%.rust.o: target/x86_64-linux-kernel/debug/lib%.a
69
$(LD) -r -o $@ --whole-archive $<
710

11+
else
12+
KDIR ?= /lib/modules/$(shell uname -r)/build
13+
CC ?= clang
14+
815
all:
9-
$(MAKE) -C $(KDIR) M=$(CURDIR)
16+
$(MAKE) -C $(KDIR) M=$(CURDIR) CC=$(CC)
1017

1118
clean:
12-
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
19+
$(MAKE) -C $(KDIR) M=$(CURDIR) CC=$(CC) clean
20+
endif

kernel-cflags-finder/.gitignore

Lines changed: 0 additions & 13 deletions
This file was deleted.

kernel-cflags-finder/Makefile

Lines changed: 0 additions & 36 deletions
This file was deleted.

kernel-cflags-finder/README.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

tests/Makefile

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
1+
ifneq ($(KERNELRELEASE),)
12
obj-m := testmodule.o
23
testmodule-objs := $(TEST_NAME).rust.o
3-
KDIR ?= /lib/modules/$(shell uname -r)/build
4+
5+
$(src)/target/x86_64-linux-kernel/debug/lib%.a: $(src)/$(TEST_PATH)/Cargo.toml $(wildcard $(src)/$(TEST_PATH)/src/*.rs)
6+
cd $(src)/$(TEST_PATH); env -u MAKE -u MAKEFLAGS KERNEL_CLFAGS="$(c_flags)" RUSTFLAGS="-Dwarnings" CARGO_TARGET_DIR=../target cargo build -Z build-std=core,alloc --target=x86_64-linux-kernel
47

58
%.rust.o: target/x86_64-linux-kernel/debug/lib%.a
69
$(LD) -r -o $@ --whole-archive $<
710

11+
else
12+
KDIR ?= /lib/modules/$(shell uname -r)/build
13+
CC ?= clang
14+
815
all:
9-
$(MAKE) -C $(KDIR) M=$(CURDIR)
16+
$(MAKE) -C $(KDIR) M=$(CURDIR) CC=$(CC)
1017

1118
clean:
12-
$(MAKE) -C $(KDIR) M=$(CURDIR) clean
19+
$(MAKE) -C $(KDIR) M=$(CURDIR) CC=$(CC) clean
20+
endif

tests/run_tests.py

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,11 @@ def main():
2525
continue
2626

2727
print("+ [{}]".format(path))
28-
run(
29-
"cargo", "build", "-Zbuild-std=core,alloc",
30-
"--target", "x86_64-linux-kernel",
31-
cwd=os.path.join(BASE_DIR, path),
32-
environ=dict(
33-
os.environ,
34-
RUSTFLAGS="-Dwarnings",
35-
CARGO_TARGET_DIR=os.path.relpath(
36-
os.path.join(BASE_DIR, "target"),
37-
os.path.join(BASE_DIR, path)
38-
),
39-
XBUILD_SYSROOT_PATH=os.path.join(BASE_DIR, "target-sysroot"),
40-
)
41-
)
4228

4329
run(
4430
"make", "-C", BASE_DIR,
4531
"TEST_NAME={}_tests".format(path.replace("-", "_")),
32+
"TEST_PATH={}".format(path),
4633
)
4734
# TODO: qemu
4835
run(

0 commit comments

Comments
 (0)