c2rust_build_paths/
lib.rs

1use std::{
2    env,
3    ffi::OsStr,
4    path::{Path, PathBuf},
5    process::{Command, Stdio},
6    str,
7};
8
9use print_bytes::println_lossy;
10
11fn print_cargo_path(name: &str, path: &Path) {
12    print!("cargo:{name}");
13    println_lossy(path);
14}
15
16pub struct SysRoot {
17    path: PathBuf,
18}
19
20impl SysRoot {
21    pub fn resolve() -> Self {
22        let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
23        let output = Command::new(rustc)
24            .args(&["--print", "sysroot"])
25            .output()
26            .expect("could not invoke `rustc` to find rust sysroot");
27        // trim, but `str::trim` doesn't exist on `[u8]`
28        let path = output
29            .stdout
30            .as_slice()
31            .split(|c| c.is_ascii_whitespace())
32            .next()
33            .unwrap_or_default();
34        #[cfg(unix)]
35        let path = {
36            use std::os::unix::ffi::OsStrExt;
37
38            OsStr::from_bytes(path)
39        };
40        #[cfg(not(unix))]
41        let path = {
42            // Windows is hard, so just require UTF-8
43            let path = str::from_utf8(path).expect("`rustc --print sysroot` is not UTF-8");
44            OsStr::new(path)
45        };
46        let path = Path::new(path).to_owned();
47        Self { path }
48    }
49
50    pub fn sysroot(&self) -> &Path {
51        self.path.as_path()
52    }
53
54    pub fn lib(&self) -> PathBuf {
55        self.sysroot().join("lib")
56    }
57
58    pub fn rustlib(&self) -> PathBuf {
59        let target = env::var_os("TARGET").expect("cargo should set $TARGET");
60        [
61            self.sysroot(),
62            Path::new("lib"),
63            Path::new("rustlib"),
64            Path::new(&target),
65            Path::new("lib"),
66        ]
67        .iter()
68        .collect()
69    }
70
71    pub fn link_rustc_private(&self) {
72        let lib = self.lib();
73        print_cargo_path("rustc-link-search=native=", &lib);
74        print_cargo_path("rustc-link-arg=-Wl,-rpath,", &lib);
75    }
76}
77
78pub fn find_llvm_config() -> Option<PathBuf> {
79    // Explicitly provided path in LLVM_CONFIG_PATH
80    env::var_os("LLVM_CONFIG_PATH")
81        .map(PathBuf::from)
82        .or_else(|| {
83            // Relative to LLVM_LIB_DIR
84            env::var_os("LLVM_LIB_DIR")
85                .map(PathBuf::from)
86                .map(|mut lib_dir| {
87                    lib_dir.push("../bin/llvm-config");
88                    lib_dir.canonicalize().unwrap()
89                })
90        })
91        .or_else(|| {
92            // In PATH
93            [
94                "llvm-config-18",
95                "llvm-config-17",
96                "llvm-config-16",
97                "llvm-config-15",
98                "llvm-config-14",
99                "llvm-config-13",
100                "llvm-config-12",
101                "llvm-config-11",
102                "llvm-config-10",
103                "llvm-config-9",
104                "llvm-config-8",
105                "llvm-config-7",
106                "llvm-config-7.0",
107                "llvm-config",
108                // Homebrew install locations on Intel macOS
109                "/usr/local/opt/llvm@18/bin/llvm-config",
110                "/usr/local/opt/llvm@17/bin/llvm-config",
111                "/usr/local/opt/llvm@16/bin/llvm-config",
112                "/usr/local/opt/llvm@15/bin/llvm-config",
113                "/usr/local/opt/llvm@14/bin/llvm-config",
114                "/usr/local/opt/llvm@13/bin/llvm-config",
115                "/usr/local/opt/llvm@12/bin/llvm-config",
116                "/usr/local/opt/llvm@11/bin/llvm-config",
117                "/usr/local/opt/llvm@10/bin/llvm-config",
118                "/usr/local/opt/llvm@9/bin/llvm-config",
119                "/usr/local/opt/llvm@8/bin/llvm-config",
120                "/usr/local/opt/llvm/bin/llvm-config",
121                // Homebrew install locations on Apple Silicon macOS
122                "/opt/homebrew/opt/llvm@18/bin/llvm-config",
123                "/opt/homebrew/opt/llvm@17/bin/llvm-config",
124                "/opt/homebrew/opt/llvm@16/bin/llvm-config",
125                "/opt/homebrew/opt/llvm@15/bin/llvm-config",
126                "/opt/homebrew/opt/llvm@14/bin/llvm-config",
127                "/opt/homebrew/opt/llvm@13/bin/llvm-config",
128                "/opt/homebrew/opt/llvm@12/bin/llvm-config",
129                "/opt/homebrew/opt/llvm@11/bin/llvm-config",
130                "/opt/homebrew/opt/llvm@10/bin/llvm-config",
131                "/opt/homebrew/opt/llvm@9/bin/llvm-config",
132                "/opt/homebrew/opt/llvm@8/bin/llvm-config",
133                "/opt/homebrew/opt/llvm/bin/llvm-config",
134            ]
135            .iter()
136            .map(Path::new)
137            .filter(|c| {
138                Command::new(c)
139                    .stdout(Stdio::null())
140                    .stderr(Stdio::null())
141                    .spawn()
142                    .is_ok()
143            })
144            .map(PathBuf::from)
145            .next()
146        })
147}