1 use std::env; 2 use std::ffi::OsStr; 3 use std::path::{Path, PathBuf}; 4 5 pub(crate) enum TargetDir { 6 Path(PathBuf), 7 Unknown, 8 } 9 find_target_dir(out_dir: &Path) -> TargetDir10pub(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 } else { 16 return TargetDir::Unknown; 17 }; 18 } 19 20 // fs::canonicalize on Windows produces UNC paths which cl.exe is unable to 21 // handle in includes. 22 // https://github.com/rust-lang/rust/issues/42869 23 // https://github.com/alexcrichton/cc-rs/issues/169 24 let mut also_try_canonical = cfg!(not(windows)); 25 26 let mut dir = out_dir.to_owned(); 27 loop { 28 if dir.join(".rustc_info.json").exists() 29 || dir.join("CACHEDIR.TAG").exists() 30 || dir.file_name() == Some(OsStr::new("target")) 31 && dir 32 .parent() 33 .map_or(false, |parent| parent.join("Cargo.toml").exists()) 34 { 35 return TargetDir::Path(dir); 36 } 37 if dir.pop() { 38 continue; 39 } 40 if also_try_canonical { 41 if let Ok(canonical_dir) = out_dir.canonicalize() { 42 dir = canonical_dir; 43 also_try_canonical = false; 44 continue; 45 } 46 } 47 return TargetDir::Unknown; 48 } 49 } 50