use std::fs;
use std::path::Path;
use crate::common::{make_executable, run_rsconstruct, write_file};
const FAKE_MAKE: &str = r#"#!/usr/bin/env python3
import os
import sys
m_dir = None
subcommand = None
for arg in sys.argv[1:]:
if arg.startswith("M="):
m_dir = arg[2:]
elif arg in ("modules", "clean"):
subcommand = arg
if subcommand == "modules":
kbuild = os.path.join(m_dir, "Kbuild")
name = None
with open(kbuild) as handle:
for line in handle:
if line.startswith("obj-m"):
# obj-m := <name>.o
name = line.split(":=", 1)[1].strip()[:-len(".o")]
with open(os.path.join(m_dir, name + ".ko"), "wb") as handle:
handle.write(b"FAKE-KO-BYTES")
elif subcommand == "clean":
for root, _dirs, files in os.walk(m_dir):
for filename in files:
if filename.endswith(".ko"):
os.unlink(os.path.join(root, filename))
sys.exit(0)
"#;
fn install_fake_make(project: &Path) -> String {
let make_path = project.join("bin").join("make");
fs::create_dir_all(make_path.parent().unwrap()).unwrap();
fs::write(&make_path, FAKE_MAKE).unwrap();
make_executable(&make_path);
make_path.to_string_lossy().into_owned()
}
#[test]
fn linux_module_root_level_manifest_output_survives_clean() {
let temp = tempfile::TempDir::new().unwrap();
let project = temp.path();
let make = install_fake_make(project);
fs::create_dir_all(project.join("kdir")).unwrap();
let kdir = project.join("kdir").to_string_lossy().into_owned();
write_file(project, "top.c", "int top;\n");
write_file(project, "helper.c", "int helper;\n");
write_file(
project,
"linux-module.yaml",
&format!(
"make: {make}\nkdir: {kdir}\nmodules:\n - name: mymod\n sources: [top.c, helper.c]\n"
),
);
write_file(project, "rsconstruct.toml", "[processor.linux_module]\nsrc_dirs = [\".\"]\n");
let output = run_rsconstruct(project, &["build"]);
assert!(
output.status.success(),
"build failed: {}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
let ko = project.join("out/linux-module/mymod.ko");
assert!(ko.exists(), "output module not produced at {}", ko.display());
assert_eq!(fs::read(&ko).unwrap(), b"FAKE-KO-BYTES");
assert!(!project.join("mymod.ko").exists(), "source .ko not cleaned up");
assert!(!project.join("Kbuild").exists(), "generated Kbuild not removed");
}
#[test]
fn linux_module_subdir_manifest_builds() {
let temp = tempfile::TempDir::new().unwrap();
let project = temp.path();
let make = install_fake_make(project);
fs::create_dir_all(project.join("kdir")).unwrap();
let kdir = project.join("kdir").to_string_lossy().into_owned();
write_file(project, "drivers/hello/main.c", "int hello;\n");
write_file(
project,
"drivers/hello/linux-module.yaml",
&format!("make: {make}\nkdir: {kdir}\nmodules:\n - name: hello\n sources: [main.c]\n"),
);
write_file(project, "rsconstruct.toml", "[processor.linux_module]\nsrc_dirs = [\"drivers\"]\n");
let output = run_rsconstruct(project, &["build"]);
assert!(
output.status.success(),
"build failed: {}\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr),
);
let ko = project.join("out/linux-module/drivers/hello/hello.ko");
assert!(ko.exists(), "output module not produced at {}", ko.display());
assert_eq!(fs::read(&ko).unwrap(), b"FAKE-KO-BYTES");
assert!(!project.join("drivers/hello/hello.ko").exists(), "source .ko not cleaned up");
assert!(!project.join("drivers/hello/Kbuild").exists(), "generated Kbuild not removed");
}