cxx_build/
paths.rs

1use crate::error::Result;
2use crate::gen::fs;
3use std::ffi::OsStr;
4use std::path::{Component, Path, PathBuf};
5
6pub(crate) fn manifest_dir() -> Result<PathBuf> {
7    crate::env_os("CARGO_MANIFEST_DIR").map(PathBuf::from)
8}
9
10pub(crate) fn out_dir() -> Result<PathBuf> {
11    crate::env_os("OUT_DIR").map(PathBuf::from)
12}
13
14// Given a path provided by the user, determines where generated files related
15// to that path should go in our out dir. In particular we don't want to
16// accidentally write generated code upward of our out dir, even if the user
17// passed a path containing lots of `..` or an absolute path.
18pub(crate) fn local_relative_path(path: &Path) -> PathBuf {
19    let mut rel_path = PathBuf::new();
20    for component in path.components() {
21        match component {
22            Component::Prefix(_) | Component::RootDir | Component::CurDir => {}
23            Component::ParentDir => drop(rel_path.pop()), // noop if empty
24            Component::Normal(name) => rel_path.push(name),
25        }
26    }
27    rel_path
28}
29
30pub(crate) trait PathExt {
31    fn with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf;
32}
33
34impl PathExt for Path {
35    fn with_appended_extension(&self, suffix: impl AsRef<OsStr>) -> PathBuf {
36        let mut file_name = self.file_name().unwrap().to_owned();
37        file_name.push(suffix);
38        self.with_file_name(file_name)
39    }
40}
41
42#[cfg(unix)]
43pub(crate) fn symlink_or_copy(
44    path_for_symlink: impl AsRef<Path>,
45    _path_for_copy: impl AsRef<Path>,
46    link: impl AsRef<Path>,
47) -> fs::Result<()> {
48    fs::symlink_file(path_for_symlink, link)
49}
50
51#[cfg(windows)]
52pub(crate) fn symlink_or_copy(
53    path_for_symlink: impl AsRef<Path>,
54    path_for_copy: impl AsRef<Path>,
55    link: impl AsRef<Path>,
56) -> fs::Result<()> {
57    // Pre-Windows 10, symlinks require admin privileges. Since Windows 10, they
58    // require Developer Mode. If it fails, fall back to copying the file.
59    let path_for_symlink = path_for_symlink.as_ref();
60    let link = link.as_ref();
61    if fs::symlink_file(path_for_symlink, link).is_err() {
62        let path_for_copy = path_for_copy.as_ref();
63        fs::copy(path_for_copy, link)?;
64    }
65    Ok(())
66}
67
68#[cfg(not(any(unix, windows)))]
69pub(crate) fn symlink_or_copy(
70    _path_for_symlink: impl AsRef<Path>,
71    path_for_copy: impl AsRef<Path>,
72    copy: impl AsRef<Path>,
73) -> fs::Result<()> {
74    fs::copy(path_for_copy, copy)?;
75    Ok(())
76}