use std::path::{Path, PathBuf};
use anyhow::Result;
use walkdir::WalkDir;
pub fn collect_cuda_files(path: &Path, filter: Option<&str>) -> Result<Vec<PathBuf>> {
if path.is_file() {
return Ok(vec![path.to_path_buf()]);
}
if !path.is_dir() {
anyhow::bail!("input path does not exist: {}", path.display());
}
let mut out = Vec::new();
for entry in WalkDir::new(path)
.follow_links(false)
.into_iter()
.filter_map(|e| e.ok())
{
let p = entry.path();
if !p.is_file() {
continue;
}
let Some(ext) = p.extension().and_then(|s| s.to_str()) else {
continue;
};
if ext != "cu" && ext != "cuh" {
continue;
}
if let Some(f) = filter {
if !p.to_string_lossy().contains(f) {
continue;
}
}
out.push(p.to_path_buf());
}
out.sort();
Ok(out)
}
pub fn map_output_path(input_root: &Path, output_root: &Path, target: &str, file: &Path) -> PathBuf {
let rel = file.strip_prefix(input_root).unwrap_or(file);
let stem = rel.file_stem().and_then(|s| s.to_str()).unwrap_or("out");
let parent = rel.parent().map(Path::to_path_buf).unwrap_or_default();
let mut out = output_root.join(target).join(parent);
let ext = target_extension(target);
out.push(format!("{stem}.{ext}"));
out
}
pub fn ensure_parent_dir(p: &Path) -> std::io::Result<()> {
if let Some(parent) = p.parent() {
std::fs::create_dir_all(parent)?;
}
Ok(())
}
fn target_extension(target: &str) -> &'static str {
match target {
"rust" => "rs",
"opencl" => "cl",
"sycl" => "sycl.cpp",
"hip" => "hip.cpp",
_ => "cpp",
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::tempdir;
#[test]
fn collects_cu_files_in_directory() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("a.cu"), "__global__ void k() {}").unwrap();
fs::write(dir.path().join("b.cuh"), "// header").unwrap();
fs::write(dir.path().join("c.cpp"), "// not cuda").unwrap();
let got = collect_cuda_files(dir.path(), None).unwrap();
let names: Vec<_> = got.iter().filter_map(|p| p.file_name()).collect();
assert!(names.iter().any(|n| *n == "a.cu"));
assert!(names.iter().any(|n| *n == "b.cuh"));
assert!(!names.iter().any(|n| *n == "c.cpp"));
}
#[test]
fn filter_substring_works() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("foo_kernel.cu"), "").unwrap();
fs::write(dir.path().join("bar_helper.cu"), "").unwrap();
let got = collect_cuda_files(dir.path(), Some("foo")).unwrap();
assert_eq!(got.len(), 1);
}
}