use std::path::Path;
use std::process::{Command, Stdio};
use std::{env, fs, path::PathBuf};
const DOCS_RS: &str = "DOCS_RS";
const OLM_LINK_VARIANT_ENV: &str = "OLM_LINK_VARIANT";
fn main() {
let olm_link_variant = env::var(OLM_LINK_VARIANT_ENV).unwrap_or_else(|_| "static".to_string());
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let docs_rs = match env::var(DOCS_RS) {
Ok(x) => x == "1",
_ => false,
};
if !docs_rs {
if target_arch == "wasm32" {
if olm_link_variant == "static" {
wasm_build(olm_link_variant);
} else {
panic!("WASM32 cannot be linked dynamicly");
}
} else {
native_build(olm_link_variant);
}
println!("cargo:rerun-if-env-changed={}", OLM_LINK_VARIANT_ENV);
}
}
fn native_build(olm_link_variant: String) {
let manifest_dir = match env::var_os("CARGO_MANIFEST_DIR") {
Some(d) => d,
None => panic!("Unable to read manifest dir"),
};
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
let src = PathBuf::from(&manifest_dir).join("olm");
let mut cmake = cmake::Config::new(src);
cmake.define("BUILD_SHARED_LIBS", "NO");
cmake.define("OLM_TESTS", "OFF");
if target_os == "android" {
if let Ok(ndk) = std::env::var("ANDROID_NDK") {
let ndk_root = PathBuf::from(ndk);
let toolchain_path = PathBuf::from("build/cmake/android.toolchain.cmake");
let toolchain_file = ndk_root.join(toolchain_path);
cmake
.define("CMAKE_SYSTEM_NAME", "Android")
.define("CMAKE_SYSTEM_VERSION", "30")
.define("CMAKE_ANDROID_NDK", ndk_root)
.define("CMAKE_TOOLCHAIN_FILE", toolchain_file);
} else {
panic!(
"please set the ANDROID_NDK environment variable to your Android NDK instalation"
);
}
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let abi = match target_arch.as_str() {
"aarch64" => "arm64-v8a",
"arm" => "armeabi-v7a",
"x86_64" => "x86_64",
"x86" => "x86",
_ => panic!(
"Unsupported target arch {} given, if this is an error please report a bug",
target_arch
),
};
cmake.define("ANDROID_ABI", abi);
}
if target_os == "ios" {
cmake.define("CMAKE_SYSTEM_NAME", "iOS");
cmake.define("CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_ALLOWED", "NO");
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
if target_arch.as_str() == "x86_64" {
cmake.build_arg("-sdk");
cmake.build_arg("iphonesimulator");
}
let osx_architectures = match target_arch.as_str() {
"aarch64" => "arm64",
"x86_64" => "x86_64",
_ => panic!(
"Unsupported target arch {} given, if this is an error please report a bug",
target_arch
),
};
cmake.define("CMAKE_OSX_ARCHITECTURES", osx_architectures);
cmake.generator("Xcode");
}
let dst = cmake.build();
if Path::new(&format!("{}/lib64", dst.display())).exists() {
println!("cargo:rustc-link-search=native={}/lib64", dst.display());
} else {
println!("cargo:rustc-link-search=native={}/lib", dst.display());
}
println!("cargo:rustc-link-lib={}=olm", olm_link_variant);
if target_os == "linux" || target_os == "android" || target_os == "illumos" {
println!("cargo:rustc-link-lib=stdc++");
}
if target_os == "freebsd" || target_os == "macos" || target_os == "ios" {
println!("cargo:rustc-link-lib=c++");
}
}
fn wasm_build(olm_link_variant: String) {
let manifest_dir = match env::var_os("CARGO_MANIFEST_DIR") {
Some(d) => d,
None => panic!("Unable to read manifest dir"),
};
let src_file = "build/wasm/libolm.a";
let src = PathBuf::from(&manifest_dir).join("olm");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let dst = PathBuf::from(&out_path).join("build");
let _ = fs::create_dir(&dst);
let dst_file = dst.join("libolm.a");
if !dst_file.exists() {
run(Command::new("make").arg("wasm").current_dir(&src));
let _ = fs::copy(&src.join(src_file), &dst_file);
}
println!("cargo:rustc-link-search={}", dst.display());
println!("cargo:rustc-link-lib={}=olm", olm_link_variant);
}
fn run(cmd: &mut Command) {
assert!(cmd
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
.unwrap()
.success());
}