Skip to main content

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-21",
95                "llvm-config-20",
96                "llvm-config-19",
97                "llvm-config-18",
98                "llvm-config-17",
99                "llvm-config-16",
100                "llvm-config-15",
101                "llvm-config-14",
102                "llvm-config-13",
103                "llvm-config-12",
104                "llvm-config-11",
105                "llvm-config-10",
106                "llvm-config-9",
107                "llvm-config-8",
108                "llvm-config-7",
109                "llvm-config-7.0",
110                "llvm-config",
111                // Homebrew install locations on Intel macOS
112                "/usr/local/opt/llvm@21/bin/llvm-config",
113                "/usr/local/opt/llvm@20/bin/llvm-config",
114                "/usr/local/opt/llvm@19/bin/llvm-config",
115                "/usr/local/opt/llvm@18/bin/llvm-config",
116                "/usr/local/opt/llvm@17/bin/llvm-config",
117                "/usr/local/opt/llvm@16/bin/llvm-config",
118                "/usr/local/opt/llvm@15/bin/llvm-config",
119                "/usr/local/opt/llvm@14/bin/llvm-config",
120                "/usr/local/opt/llvm@13/bin/llvm-config",
121                "/usr/local/opt/llvm@12/bin/llvm-config",
122                "/usr/local/opt/llvm@11/bin/llvm-config",
123                "/usr/local/opt/llvm@10/bin/llvm-config",
124                "/usr/local/opt/llvm@9/bin/llvm-config",
125                "/usr/local/opt/llvm@8/bin/llvm-config",
126                "/usr/local/opt/llvm/bin/llvm-config",
127                // Homebrew install locations on Apple Silicon macOS
128                "/opt/homebrew/opt/llvm@21/bin/llvm-config",
129                "/opt/homebrew/opt/llvm@20/bin/llvm-config",
130                "/opt/homebrew/opt/llvm@19/bin/llvm-config",
131                "/opt/homebrew/opt/llvm@18/bin/llvm-config",
132                "/opt/homebrew/opt/llvm@17/bin/llvm-config",
133                "/opt/homebrew/opt/llvm@16/bin/llvm-config",
134                "/opt/homebrew/opt/llvm@15/bin/llvm-config",
135                "/opt/homebrew/opt/llvm@14/bin/llvm-config",
136                "/opt/homebrew/opt/llvm@13/bin/llvm-config",
137                "/opt/homebrew/opt/llvm@12/bin/llvm-config",
138                "/opt/homebrew/opt/llvm@11/bin/llvm-config",
139                "/opt/homebrew/opt/llvm@10/bin/llvm-config",
140                "/opt/homebrew/opt/llvm@9/bin/llvm-config",
141                "/opt/homebrew/opt/llvm@8/bin/llvm-config",
142                "/opt/homebrew/opt/llvm/bin/llvm-config",
143            ]
144            .iter()
145            .map(Path::new)
146            .filter(|c| {
147                Command::new(c)
148                    .stdout(Stdio::null())
149                    .stderr(Stdio::null())
150                    .spawn()
151                    .is_ok()
152            })
153            .map(PathBuf::from)
154            .next()
155        })
156}