run_clang_tidy/
run_clang_tidy.rs1use std::{
2 path::{Path, PathBuf},
3 process::Command,
4};
5
6use clap::{arg, Parser};
7use openvm_scripts::{
8 find_cuda_include_dirs, find_files_with_extension, get_cuda_dep_common_include_dirs,
9};
10
11#[derive(Parser)]
12#[command(author, version, about = "Run Clang-Tidy on CUDA files")]
13pub struct Args {
14 directory: PathBuf,
16
17 #[arg(long, default_value = "clang-tidy")]
19 clang_tidy: String,
20
21 #[arg(long, default_value = "/usr/local/cuda")]
23 cuda_path: String,
24
25 #[arg(long, default_value = "80")]
27 cuda_arch: String,
28}
29
30fn run_clang_tidy_single(
31 file: &Path,
32 clang_tidy: &str,
33 cuda_path: &str,
34 cuda_arch: &str,
35 includes: &[String],
36) -> eyre::Result<bool> {
37 let mut cmd = Command::new(clang_tidy);
38
39 cmd.args([
40 "--checks='*'",
41 "--warnings-as-errors='*'",
42 "--header-filter='.*'",
43 "--extra-arg=-Wno-unknown-cuda-version",
44 ])
45 .arg(file.to_str().unwrap())
46 .args(["--", "-x", "cuda", "-std=c++17"])
47 .arg(format!("--cuda-path={cuda_path}"))
48 .arg(format!("--cuda-gpu-arch=sm_{cuda_arch}"))
49 .arg("-D__CUDACC__")
50 .arg(format!("-I{cuda_path}/include"));
51
52 let cccl_path = PathBuf::from(cuda_path).join("include").join("cccl");
54 if cccl_path.exists() {
55 cmd.arg(format!("-I{}", cccl_path.display()));
56 }
57
58 for include in includes {
59 cmd.arg(format!("-I{include}"));
60 }
61
62 println!("Running for {}", file.display());
63
64 let status = cmd.status()?;
65 Ok(status.success())
66}
67
68fn main() -> eyre::Result<()> {
69 let args = Args::parse();
70 let include_dirs = find_cuda_include_dirs(&args.directory)
71 .iter()
72 .chain(get_cuda_dep_common_include_dirs().iter())
73 .map(|p| p.to_string_lossy().to_string())
74 .collect::<Vec<_>>();
75 let files = find_files_with_extension(&args.directory, "cu");
76
77 if files.is_empty() {
78 println!("No .cu files found.");
79 return Ok(());
80 }
81
82 let mut failures = Vec::new();
83
84 for file in &files {
85 match run_clang_tidy_single(
86 file,
87 &args.clang_tidy,
88 &args.cuda_path,
89 &args.cuda_arch,
90 &include_dirs,
91 ) {
92 Ok(true) => {}
93 Ok(false) => failures.push(file),
94 Err(e) => {
95 eprintln!("Error running clang-tidy on {}: {}", file.display(), e);
96 failures.push(file);
97 }
98 }
99 }
100
101 println!("\n=== Summary ===");
102 println!(
103 "Total: {} Succeeded: {} Failed: {}",
104 files.len(),
105 files.len() - failures.len(),
106 failures.len()
107 );
108
109 if !failures.is_empty() {
110 println!("Failed files:");
111 for file in failures {
112 println!(" {}", file.display());
113 }
114 return Err(eyre::eyre!("Failed files found"));
115 }
116 Ok(())
117}