blob: 16bf12a3c46661c459d9f4f52571bf7b0ebbe794 [file] [log] [blame]
David Tolnay7db73692019-10-20 14:51:12 -04001use crate::error::{Error, Result};
2use std::env;
3use std::fs;
4use std::os;
5use std::path::{Path, PathBuf};
6
7fn out_dir() -> Result<PathBuf> {
8 env::var_os("OUT_DIR")
9 .map(PathBuf::from)
10 .ok_or(Error::MissingOutDir)
11}
12
13pub(crate) fn cc_build() -> cc::Build {
14 try_cc_build().unwrap_or_default()
15}
16
17fn try_cc_build() -> Result<cc::Build> {
18 let target_dir = target_dir()?;
19
20 let mut build = cc::Build::new();
21 build.include(target_dir.join("cxxbridge"));
22 build.include(target_dir.parent().unwrap());
23 Ok(build)
24}
25
26// Symlink the header file into a predictable place. The header generated from
27// path/to/mod.rs gets linked to targets/cxxbridge/path/to/mod.h.
28pub(crate) fn symlink_header(path: &Path, original: &Path) {
29 let _ = try_symlink_header(path, original);
30}
31
32fn try_symlink_header(path: &Path, original: &Path) -> Result<()> {
33 let suffix = relative_to_parent_of_target_dir(original)?;
David Tolnay0c88e032020-01-28 00:43:51 -080034 let ref dst = target_dir()?.join("cxxbridge").join(suffix);
David Tolnay7db73692019-10-20 14:51:12 -040035
36 fs::create_dir_all(dst.parent().unwrap())?;
David Tolnay0c88e032020-01-28 00:43:51 -080037 let _ = fs::remove_file(dst);
David Tolnay7db73692019-10-20 14:51:12 -040038 #[cfg(unix)]
39 os::unix::fs::symlink(path, dst)?;
40 #[cfg(windows)]
41 os::windows::fs::symlink_file(path, dst)?;
42
43 Ok(())
44}
45
46fn relative_to_parent_of_target_dir(original: &Path) -> Result<PathBuf> {
47 let target_dir = target_dir()?;
David Tolnay015c5e82020-01-26 16:31:48 -080048 let mut outer = target_dir.parent().unwrap();
David Tolnay7db73692019-10-20 14:51:12 -040049 let original = original.canonicalize()?;
David Tolnay015c5e82020-01-26 16:31:48 -080050 loop {
51 if let Ok(suffix) = original.strip_prefix(outer) {
52 return Ok(suffix.to_owned());
53 }
54 match outer.parent() {
55 Some(parent) => outer = parent,
56 None => return Ok(original.components().skip(1).collect()),
57 }
58 }
David Tolnay7db73692019-10-20 14:51:12 -040059}
60
61pub(crate) fn out_with_extension(path: &Path, ext: &str) -> Result<PathBuf> {
62 let mut file_name = path.file_name().unwrap().to_owned();
63 file_name.push(ext);
64
65 let out_dir = out_dir()?;
66 let rel = relative_to_parent_of_target_dir(path)?;
67 Ok(out_dir.join(rel).with_file_name(file_name))
68}
69
70fn target_dir() -> Result<PathBuf> {
71 let mut dir = out_dir()?.canonicalize()?;
72 loop {
73 if dir.ends_with("target") {
74 return Ok(dir);
75 }
76 if !dir.pop() {
77 return Err(Error::TargetDir);
78 }
79 }
80}