fn build_imath() -> std::string::String {
cmake::Config::new("thirdparty/Imath")
.profile("Release")
.define("IMATH_IS_SUBPROJECT", "ON")
.define("BUILD_TESTING", "OFF")
.define("BUILD_SHARED_LIBS", "ON")
.build()
.to_str()
.expect("Unable to convert imath_root to str")
.to_string()
}
fn build_openexr(imath_root: &str) -> std::string::String {
cmake::Config::new("thirdparty/openexr")
.define("CMAKE_PREFIX_PATH", &imath_root)
.profile("Release")
.define("OPENEXR_IS_SUBPROJECT", "ON")
.define("BUILD_TESTING", "OFF")
.define("OPENEXR_INSTALL_EXAMPLES", "OFF")
.define("BUILD_SHARED_LIBS", "ON")
.build()
.to_str()
.expect("Unable to convert openexr_root to str")
.to_string()
}
use regex::Regex;
use std::path::Path;
#[derive(Debug)]
struct DylibPathInfo {
path: String,
basename: String,
libname: String,
}
fn is_dylib_path(s: &str, re: &Regex) -> Option<DylibPathInfo> {
if let Some(m) = re.captures_iter(s).next() {
if let Some(c0) = m.get(0) {
if let Some(c1) = m.get(1) {
return Some(DylibPathInfo {
path: s.to_string(),
basename: c0.as_str().to_string(),
libname: c1.as_str().to_string(),
});
}
}
}
None
}
fn get_linking_from_cmake(link_txt_path: &Path) -> Vec<DylibPathInfo> {
let link_txt = std::fs::read_to_string(link_txt_path).expect(&format!(
"Could not read link_txt_path: {}",
link_txt_path.display()
));
let re = Regex::new(
r"lib([^/]+?)(?:\.dylib|\.so|\.so.\d+|\.so.\d+.\d+|\.so.\d+.\d+.\d+)$",
)
.unwrap();
let mut link_txt = link_txt.split(' ');
while let Some(s) = link_txt.next() {
if s == "-o" {
let _ = link_txt.next();
break;
}
}
link_txt.filter_map(|s| is_dylib_path(s, &re)).collect()
}
fn create_symlinks(target_dir: &Path, d: &DylibPathInfo) {
if d.basename.ends_with(".so") {
return;
}
if d.basename.matches(".").count() < 4 {
panic!("so basename has bad number of periods: {}", d.basename);
}
let toks: Vec<&str> = d.basename.split('.').collect();
let symname = target_dir.join(format!("lib{}.so", &d.libname));
let symname1 = format!("{}", toks[0..toks.len() - 2].join("."));
if !target_dir.join(&symname1).exists() {
std::os::unix::fs::symlink(&d.basename, &target_dir.join(&symname1))
.unwrap();
}
if !symname.exists() {
std::os::unix::fs::symlink(&symname1, &symname).unwrap();
}
}
fn main() {
let build_libraries = if std::env::var("CMAKE_PREFIX_PATH").is_ok() {
if let Ok(obl) = std::env::var("OPENEXR_BUILD_LIBRARIES") {
obl == "1"
} else {
false
}
} else {
true
};
let clib_name = "vfxpreopenexr-c";
let clib_versioned_name = "vfxpreopenexr-c-0_0";
let dst = if build_libraries {
let imath_root = build_imath();
let openexr_root = build_openexr(&imath_root);
cmake::Config::new(clib_name)
.define("CMAKE_EXPORT_COMPILE_COMMANDS", "ON")
.define(
"CMAKE_PREFIX_PATH",
format!("{}/lib/cmake;{}/lib/cmake", imath_root, openexr_root),
)
.build()
} else {
cmake::Config::new(clib_name)
.define("CMAKE_EXPORT_COMPILE_COMMANDS", "ON")
.build()
};
let link_txt_path = Path::new(&dst)
.join("build")
.join("CMakeFiles")
.join(format!("{}-shared.dir", clib_versioned_name))
.join("link.txt");
let target_dir = dst.parent().unwrap().parent().unwrap().parent().unwrap();
let dylibs = get_linking_from_cmake(&link_txt_path);
println!("cargo:rustc-link-search=native={}", dst.display());
println!("cargo:rustc-link-lib=static={}", clib_versioned_name);
if build_libraries {
println!("cargo:rustc-link-search=native={}", target_dir.display());
println!("cargo:warning=adding link path {}", target_dir.display());
for d in dylibs {
let to = target_dir.join(&d.basename);
std::fs::copy(&d.path, &to).unwrap();
#[cfg(target_os = "linux")]
create_symlinks(&target_dir, &d);
println!("cargo:rustc-link-lib=dylib={}", &d.libname);
println!("cargo:warning=linking to {}", &d.libname);
}
#[cfg(target_os = "linux")]
println!("cargo:rustc-env=LD_LIBRARY_PATH={}", target_dir.display());
#[cfg(target_os = "macos")]
println!("cargo:rustc-env=DYLD_LIBRARY_PATH={}", target_dir.display());
} else {
for d in dylibs {
let libdir = Path::new(&d.path).parent().unwrap();
println!("cargo:rustc-link-search=native={}", libdir.display());
println!("cargo:rustc-link-lib=dylib={}", &d.libname);
}
}
#[cfg(target_os = "linux")]
println!("cargo:rustc-link-lib=dylib=stdc++");
#[cfg(target_os = "macos")]
println!("cargo:rustc-link-lib=dylib=c++");
}