use std::{
env,
ffi::OsString,
io::{self, Error, ErrorKind},
path::{Path, PathBuf},
process::{exit, Command},
};
const ENVVAR_R_HOME: &str = "R_HOME";
fn get_r_home() -> io::Result<PathBuf> {
if let Some(r_home) = env::var_os(ENVVAR_R_HOME) {
return Ok(PathBuf::from(r_home));
}
let output = Command::new("R").arg("RHOME").output()?;
if !output.stdout.is_empty() {
let mut output=output.stdout;
if let Some(b'\n') = output.last() {
output.pop();
} if let Some(b'\r') = output.last() {
output.pop();
} if output.len()>0 {
Ok(PathBuf::from(unsafe {OsString::from_encoded_bytes_unchecked(output)}))
} else {
Err(Error::new(ErrorKind::Other, "Cannot find R home with command `R RHOME`.\nNote: Specific `$R_HOME` variable directly could solve this issue.\n The $R_HOME variable could be set automatically with `R CMD build` command if you are building an R package.\n R founded in $PATH, but cannot obtain $R_HOME from R directly (encoding not support?)"))
}
} else {
Err(Error::new(ErrorKind::Other, "Cannot find R home.\nNote: Either specific `$R_HOME` variable directly or leave R in `$PATH` could solve this issue.\n The $R_HOME variable could be set automatically with `R CMD build` command if you are building an R package.\n If you want to set it manually, its value could be the output of the command `R RHOME`"))
}
}
fn get_r_library(r_home: &Path) -> PathBuf {
let pkg_target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
match (cfg!(windows), pkg_target_arch.as_str()) {
(true, "x86_64") => Path::new(r_home).join("bin").join("x64"),
(true, "x86") => Path::new(r_home).join("bin").join("i386"),
(true, _) => panic!("Unknown architecture"),
(false, _) => Path::new(r_home).join("lib"),
}
}
struct InstallationPaths {
r_home: PathBuf,
library: PathBuf,
}
fn probe_r_paths() -> io::Result<InstallationPaths> {
let r_home = get_r_home()?;
let library = get_r_library(&r_home);
Ok(InstallationPaths { r_home, library })
}
fn main() {
let r_paths = probe_r_paths();
let r_paths = match r_paths {
Ok(result) => result,
Err(error) => {
println!("Problem locating local R install: {:?}", error);
exit(1);
}
};
println!("cargo:rustc-env=R_HOME={}", r_paths.r_home.display());
println!("cargo:r_home={}", r_paths.r_home.display());
if let Ok(r_library) = r_paths.library.canonicalize() {
println!("cargo:rustc-link-search={}", r_library.display());
}
println!("cargo:rerun-if-changed=build.rs");
}