wasmcov/
llvm.rs

1use crate::utils::run_command;
2use anyhow::{anyhow, Result};
3use regex::Regex;
4use std::sync::Once;
5
6static LLVM_TOOLING: Once = Once::new();
7static mut LLVM_TOOLING_RESULT: Option<LlvmToolingResult> = None;
8pub fn get_tooling() -> Result<&'static LlvmToolingResult> {
9    LLVM_TOOLING.call_once(|| unsafe {
10        LLVM_TOOLING_RESULT = Some(find_tooling().expect("Failed to initialize LLVM tooling"));
11    });
12    unsafe { Ok(LLVM_TOOLING_RESULT.as_ref().unwrap()) }
13}
14
15pub fn check_rustc_version() -> Result<(bool, String)> {
16    let output_str = run_command("rustc", &["--version", "--verbose"], None)?;
17    let is_nightly = output_str.contains("nightly");
18    let llvm_major_version = Regex::new(r"LLVM version: (\d+)")
19        .unwrap()
20        .captures(&output_str)
21        .and_then(|cap| cap.get(1).map(|m| m.as_str()))
22        .map(String::from)
23        .ok_or(anyhow!("Failed to parse rustc output: {}", output_str))?;
24    Ok((is_nightly, llvm_major_version))
25}
26
27pub fn check_llvm_tool_version(command: &str) -> Result<String> {
28    let output = run_command(&command, &["--version"], None)?;
29    let llvm_major_version = Regex::new(r"version (\d+)")
30        .unwrap()
31        .captures(&output)
32        .and_then(|cap| cap.get(1).map(|m| m.as_str()))
33        .map(String::from)
34        .ok_or(anyhow!("Failed to parse {command} output:\n{output}"))?;
35    Ok(llvm_major_version)
36}
37
38pub fn find_llvm_tool(tool: &str, major_version: &str) -> Result<String> {
39    let version = check_llvm_tool_version(&format!("{tool}-{major_version}"));
40    if version.is_err() {
41        let version = check_llvm_tool_version(&tool);
42        if version.is_err() {
43            return Err(anyhow!("Failed to find {tool}-{major_version}"));
44        }
45        let version = version.unwrap();
46        if version != major_version {
47            Err(anyhow!(
48                "Found {tool} version {version}, but expected {major_version}"
49            ))
50        } else {
51            Ok(tool.to_string())
52        }
53    } else {
54        Ok(format!("{tool}-{major_version}"))
55    }
56}
57
58pub struct LlvmToolingResult {
59    pub rustc_is_nightly: bool,
60    pub llvm_major_version: String,
61    pub clang: String,
62    pub llvm_cov: String,
63    pub llvm_profdata: String,
64}
65
66pub fn find_tooling() -> Result<LlvmToolingResult> {
67    let (rustc_is_nightly, llvm_major_version) = check_rustc_version()?;
68    let clang = find_llvm_tool("clang", &llvm_major_version)?;
69    let llvm_cov = find_llvm_tool("llvm-cov", &llvm_major_version)?;
70    let llvm_profdata = find_llvm_tool("llvm-profdata", &llvm_major_version)?;
71
72    Ok(LlvmToolingResult {
73        rustc_is_nightly,
74        llvm_major_version,
75        clang,
76        llvm_cov,
77        llvm_profdata,
78    })
79}
80
81/*
82#[cfg(test)]
83mod tests {
84    use super::*;
85    use regex::Regex;
86
87    // Paste your rustc --version --verbose output here
88    static RUSTC_OUTPUT: &str = "rustc 1.72.0-nightly (5ea666864 2023-06-27)\nbinary: rustc\ncommit-hash: 5ea66686467d3ec5f8c81570e7f0f16ad8dd8cc3\ncommit-date: 2023-06-27\nhost: x86_64-unknown-linux-gnu\nrelease: 1.72.0-nightly\nLLVM version: 16.0.5\n";
89
90    #[test]
91    fn test_run_command() -> Result<()> {
92        let command = "rustc";
93        let args = &["--version", "--verbose"];
94
95        let result = run_command(command, args)?;
96
97        assert_eq!(result, RUSTC_OUTPUT.to_string());
98        Ok(())
99    }
100
101    #[test]
102    fn test_check_rustc_version() -> Result<()> {
103        let result = check_rustc_version()?;
104
105        let is_nightly = RUSTC_OUTPUT.contains("nightly");
106        let llvm_major_version = Regex::new(r"LLVM version: (\d+)")
107            .unwrap()
108            .captures(RUSTC_OUTPUT)
109            .and_then(|cap| cap.get(1).map(|m| m.as_str()))
110            .map(String::from)
111            .ok_or(anyhow!("Failed to parse rustc output: {}", RUSTC_OUTPUT))?;
112
113        assert_eq!(result, (is_nightly, llvm_major_version));
114        Ok(())
115    }
116
117    #[test]
118    fn test_check_wasm_target() -> Result<()> {
119        let is_nightly = RUSTC_OUTPUT.contains("nightly");
120
121        check_wasm_target(is_nightly)?;
122
123        Ok(())
124    }
125
126    #[test]
127    fn test_check_command_availability() {
128        let command = "rustc";
129
130        let result = check_command_availability(command.to_string());
131
132        assert!(result.is_ok());
133    }
134
135    #[test]
136    fn test_verify_tooling_and_cleanup() {
137        let result = verify_tooling();
138
139        assert!(result.is_ok());
140
141        let verify_tooling_result = result.unwrap();
142    }
143}
144 */