Skip to main content

cxx_build/
target.rs

1use std::env;
2use std::ffi::OsStr;
3use std::path::{Path, PathBuf};
4
5pub(crate) enum TargetDir {
6    Path(PathBuf),
7    Unknown,
8}
9
10pub(crate) fn find_target_dir(out_dir: &Path) -> TargetDir {
11    if let Some(target_dir) = env::var_os("CARGO_TARGET_DIR") {
12        let target_dir = PathBuf::from(target_dir);
13        if target_dir.is_absolute() {
14            return TargetDir::Path(target_dir);
15        }
16        // A relative CARGO_TARGET_DIR is relative to the directory cargo was
17        // invoked from, which is not known to the build script. Fall back to
18        // searching the ancestors of OUT_DIR.
19    }
20
21    // fs::canonicalize on Windows produces UNC paths which cl.exe is unable to
22    // handle in includes.
23    // https://github.com/rust-lang/rust/issues/42869
24    // https://github.com/alexcrichton/cc-rs/issues/169
25    let mut also_try_canonical = truecfg!(not(windows));
26
27    let mut dir = out_dir.to_owned();
28    loop {
29        if dir.join(".rustc_info.json").exists()
30            || dir.join("CACHEDIR.TAG").exists()
31            || dir.file_name() == Some(OsStr::new("target"))
32                && dir
33                    .parent()
34                    .is_some_and(|parent| parent.join("Cargo.toml").exists())
35        {
36            return TargetDir::Path(dir);
37        }
38        if dir.pop() {
39            continue;
40        }
41        if also_try_canonical && let Ok(canonical_dir) = out_dir.canonicalize() {
42            dir = canonical_dir;
43            also_try_canonical = false;
44            continue;
45        }
46        return TargetDir::Unknown;
47    }
48}