Add an option to output a depfile for outside build-systems to learn the source file dependencies of the bindings. This can be used by 3rd party build system integrations to only rerun bindgen when necessary. Testing is done via CMake integration tests, since CMake is a 3rd party buildsystem which supports depfiles.
110 lines
3.9 KiB
Rust
110 lines
3.9 KiB
Rust
use std::fs::read_to_string;
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
static CBINDGEN_PATH: &str = env!("CARGO_BIN_EXE_cbindgen");
|
|
|
|
fn test_project(project_path: &str) {
|
|
let mut cmake_cmd = Command::new("cmake");
|
|
cmake_cmd.arg("--version");
|
|
cmake_cmd
|
|
.output()
|
|
.expect("CMake --version failed - Is CMake installed?");
|
|
|
|
let mut cmake_configure = Command::new("cmake");
|
|
let build_dir = PathBuf::from(project_path).join("build");
|
|
if build_dir.exists() {
|
|
std::fs::remove_dir_all(&build_dir).expect("Failed to remove old build directory");
|
|
}
|
|
let project_dir = PathBuf::from(project_path);
|
|
|
|
let cbindgen_define = format!("-DCBINDGEN_PATH={}", CBINDGEN_PATH);
|
|
cmake_configure
|
|
.arg("-S")
|
|
.arg(project_path)
|
|
.arg("-B")
|
|
.arg(&build_dir)
|
|
.arg(cbindgen_define);
|
|
let output = cmake_configure.output().expect("Failed to execute process");
|
|
let stdout_str = String::from_utf8(output.stdout).unwrap();
|
|
let stderr_str = String::from_utf8(output.stderr).unwrap();
|
|
assert!(
|
|
output.status.success(),
|
|
"Configuring test project failed: stdout: `{}`, stderr: `{}`",
|
|
stdout_str,
|
|
stderr_str
|
|
);
|
|
let depfile_path = build_dir.join("depfile.d");
|
|
assert!(
|
|
!depfile_path.exists(),
|
|
"depfile should not exist before building"
|
|
);
|
|
|
|
// Do the clean first build
|
|
let mut cmake_build = Command::new("cmake");
|
|
cmake_build.arg("--build").arg(&build_dir);
|
|
let output = cmake_build.output().expect("Failed to execute process");
|
|
assert!(output.status.success(), "Building test project failed");
|
|
let out_str = String::from_utf8(output.stdout).unwrap();
|
|
assert!(
|
|
out_str.contains("Running cbindgen"),
|
|
"cbindgen rule did not run. Output: {}",
|
|
out_str
|
|
);
|
|
|
|
assert!(
|
|
depfile_path.exists(),
|
|
"depfile does not exist after building"
|
|
);
|
|
|
|
let expected_dependencies_filepath = PathBuf::from(project_path)
|
|
.join("expectations")
|
|
.join("dependencies");
|
|
assert!(
|
|
expected_dependencies_filepath.exists(),
|
|
"Test did not define expected dependencies. Please read the Readme.md"
|
|
);
|
|
let expected_deps =
|
|
read_to_string(expected_dependencies_filepath).expect("Failed to read dependencies");
|
|
let depinfo = read_to_string(depfile_path).expect("Failed to read dependencies");
|
|
// Assumes a single rule in the file - all deps are listed to the rhs of the `:`.
|
|
let actual_deps = depinfo.split(':').collect::<Vec<_>>()[1];
|
|
// Strip the line breaks.
|
|
let actual_deps = actual_deps.replace("\\\n", " ");
|
|
// I don't want to deal with supporting escaped whitespace when splitting at whitespace,
|
|
// so the tests don't support being run in a directory containing whitespace.
|
|
assert!(
|
|
!actual_deps.contains("\\ "),
|
|
"The tests directory may not contain any whitespace"
|
|
);
|
|
let dep_list: Vec<&str> = actual_deps.split_ascii_whitespace().collect();
|
|
let expected_dep_list: Vec<String> = expected_deps
|
|
.lines()
|
|
.map(|dep| project_dir.join(dep).to_str().unwrap().to_string())
|
|
.collect();
|
|
assert_eq!(dep_list, expected_dep_list);
|
|
|
|
let output = cmake_build.output().expect("Failed to execute process");
|
|
assert!(output.status.success(), "Building test project failed");
|
|
let out_str = String::from_utf8(output.stdout).unwrap();
|
|
assert!(
|
|
!out_str.contains("Running cbindgen"),
|
|
"cbindgen rule ran on second build"
|
|
);
|
|
|
|
std::fs::remove_dir_all(build_dir).expect("Failed to remove old build directory");
|
|
()
|
|
}
|
|
|
|
macro_rules! test_file {
|
|
($test_function_name:ident, $name:expr, $file:tt) => {
|
|
#[test]
|
|
fn $test_function_name() {
|
|
test_project($file);
|
|
}
|
|
};
|
|
}
|
|
|
|
// This file is generated by build.rs
|
|
include!(concat!(env!("OUT_DIR"), "/depfile_tests.rs"));
|