use flate2::read::GzDecoder;
use std::{env, fs, io, path::PathBuf};
struct Library(&'static str, &'static str);
const fn static_lib() -> &'static str {
if cfg!(feature = "static-link") {
"static"
} else {
"dylib"
}
}
const fn build_zlib() -> bool {
cfg!(not(feature = "nozlib"))
}
const fn build_assimp() -> bool {
cfg!(feature = "build-assimp")
}
fn compiler_flags() -> Vec<&'static str> {
let mut flags = Vec::new();
if cfg!(target_env = "msvc") {
flags.push("/EHsc");
if which::which("ninja").is_ok() {
env::set_var("CMAKE_GENERATOR", "Ninja");
}
}
flags
}
fn lib_names() -> Vec<Library> {
let mut names = Vec::new();
if cfg!(target_os = "windows") && cfg!(target_env = "gnu") {
panic!("Windows GNU is not supported, assimp fails to build for some reason.\nSee https://github.com/assimp/assimp/issues/4868");
} else {
names.push(Library("assimp", static_lib()));
}
if build_assimp() && build_zlib() {
names.push(Library("zlibstatic", "static"));
} else {
names.push(Library("z", "dylib"));
}
if cfg!(target_os = "linux") {
names.push(Library("stdc++", "dylib"));
}
if cfg!(target_os = "macos") {
names.push(Library("c++", "dylib"));
}
names
}
fn build_from_source() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let build_zlib = if build_zlib() { "ON" } else { "OFF" };
let build_shared = if static_lib() == "static" {
"OFF"
} else {
"ON"
};
let mut cmake = cmake::Config::new("assimp");
cmake
.profile("Release")
.static_crt(true)
.out_dir(out_dir.join(static_lib()))
.define("BUILD_SHARED_LIBS", build_shared)
.define("ASSIMP_BUILD_ASSIMP_TOOLS", "OFF")
.define("ASSIMP_BUILD_TESTS", "OFF")
.define("ASSIMP_BUILD_ZLIB", build_zlib)
.define("LIBRARY_SUFFIX", "");
for flag in compiler_flags().iter() {
cmake.cflag(flag);
cmake.cxxflag(flag);
}
let cmake_dir = cmake.build();
println!(
"cargo:rustc-link-search=native={}",
cmake_dir.join("lib").display()
);
println!(
"cargo:rustc-link-search=native={}",
cmake_dir.join("bin").display()
);
}
fn link_from_package() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let target = env::var("TARGET").unwrap();
let crate_version = env::var("CARGO_PKG_VERSION").unwrap();
let archive_name = format!(
"russimp-{}-{}-{}.tar.gz",
crate_version,
target,
static_lib()
);
let ar_src_dir;
if option_env!("RUSSIMP_PACKAGE_DIR").is_some() {
ar_src_dir = PathBuf::from(env::var("RUSSIMP_PACKAGE_DIR").unwrap());
} else {
ar_src_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let dl_link = format!(
"https://github.com/jkvargas/russimp-sys/releases/download/v{}/{}",
crate_version, archive_name
);
match fs::File::open(ar_src_dir.join(&archive_name)) {
Ok(_) => {}
Err(_) => {
let resp = reqwest::blocking::get(dl_link).unwrap();
let mut bytes = io::Cursor::new(resp.bytes().unwrap());
let mut file = fs::File::create(ar_src_dir.join(&archive_name)).unwrap();
io::copy(&mut bytes, &mut file).unwrap();
}
}
}
dbg!(ar_src_dir.join(&archive_name));
let file = fs::File::open(ar_src_dir.join(&archive_name)).unwrap();
let mut archive = tar::Archive::new(GzDecoder::new(file));
let ar_dest_dir = out_dir.join(static_lib());
archive.unpack(&ar_dest_dir).unwrap();
println!(
"cargo:rustc-link-search=native={}",
ar_dest_dir.join("lib").display()
);
println!(
"cargo:rustc-link-search=native={}",
ar_dest_dir.join("bin").display()
);
}
fn main() {
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
println!("cargo:rustc-link-search=native=/opt/homebrew/lib/");
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
println!("cargo:rustc-link-search=native=/opt/brew/lib/");
if build_assimp() {
build_from_source();
} else if cfg!(feature = "prebuilt") {
link_from_package();
}
let config_file = "assimp/include/assimp/config.h";
let config_exists = fs::metadata(config_file).is_ok();
if !config_exists {
fs::write(config_file, "").expect(
r#"Unable to write config.h to assimp/include/assimp/,
make sure you cloned submodules with "git submodule update --init --recursive""#,
);
}
bindgen::builder()
.header("wrapper.h")
.clang_arg(format!("-I{}", out_dir.join(static_lib()).join("include").display()))
.clang_arg(format!("-I{}", "assimp/include"))
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.allowlist_type("ai.*")
.allowlist_function("ai.*")
.allowlist_var("ai.*")
.allowlist_var("AI_.*")
.derive_partialeq(true)
.derive_eq(true)
.derive_hash(true)
.derive_debug(true)
.generate()
.unwrap()
.write_to_file(out_dir.join("bindings.rs"))
.expect("Could not generate russimp bindings, for details see https://github.com/jkvargas/russimp-sys");
if !config_exists {
let _ = fs::remove_file(config_file);
}
let mut built_opts = built::Options::default();
built_opts
.set_dependencies(false)
.set_compiler(false)
.set_ci(false)
.set_cfg(false);
built::write_built_file_with_opts(&built_opts, &manifest_dir, &out_dir.join("built.rs"))
.unwrap();
for n in lib_names().iter() {
println!("cargo:rustc-link-lib={}={}", n.1, n.0);
}
}