use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::fs;
use std::io;
use ureq;
use zip;
fn download_and_setup_libs() -> Result<(), Box<dyn std::error::Error>> {
let out_dir = env::var("OUT_DIR")?;
let libs_dir = PathBuf::from(&out_dir).join("libs");
if !libs_dir.exists() {
fs::create_dir_all(&libs_dir)?;
}
let version = "v3.38.1";
let base_url = "https://dl.cryptlex.com/downloads";
#[cfg(all(target_arch="x86_64", target_os="macos"))]
let (zip_filename, lib_path) = ("LexActivator-Static-Mac.zip", "clang/x86_64/libLexActivator.a");
#[cfg(all(target_arch="aarch64", target_os="macos"))]
let (zip_filename, lib_path) = ("LexActivator-Static-Mac.zip", "clang/arm64/libLexActivator.a");
#[cfg(all(target_arch="aarch64", target_os="linux", target_env="gnu"))]
let (zip_filename, lib_path) = ("LexActivator-Static-Linux.zip", "gcc-6/arm64/libLexActivator.a");
#[cfg(all(target_arch="x86_64", target_os="linux", target_env="gnu"))]
let (zip_filename, lib_path) = ("LexActivator-Static-Linux.zip", "gcc-6/amd64/libLexActivator.a");
#[cfg(all(target_arch="x86", target_os="linux", target_env="gnu"))]
let (zip_filename, lib_path) = ("LexActivator-Static-Linux.zip", "gcc-6/i386/libLexActivator.a");
#[cfg(all(target_arch="x86_64", target_os="linux", target_env="musl"))]
let (zip_filename, lib_path) = ("LexActivator-Static-Linux.zip", "musl/amd64/libLexActivator.a");
#[cfg(all(target_arch="aarch64", target_os="linux", target_env="musl"))]
let (zip_filename, lib_path) = ("LexActivator-Static-Linux.zip", "musl/arm64/libLexActivator.a");
#[cfg(all(target_arch="x86_64", target_os="windows", target_env="msvc"))]
let (zip_filename, lib_path) = ("LexActivator-Win.zip", "vc14/x64/LexActivator.lib");
#[cfg(all(target_arch="x86", target_os="windows", target_env="msvc"))]
let (zip_filename, lib_path) = ("LexActivator-Win.zip", "vc14/x86/LexActivator.lib");
let target_dir = get_target_lib_dir(&out_dir);
if !target_dir.exists() {
fs::create_dir_all(&target_dir)?;
}
#[cfg(target_os="windows")]
let lib_file = target_dir.join("LexActivator.lib");
#[cfg(not(target_os="windows"))]
let lib_file = target_dir.join("libLexActivator.a");
if !lib_file.exists() {
println!("cargo:warning=Downloading LexActivator library for target...");
let download_url = format!("{}/{}/{}", base_url, version, zip_filename);
let temp_dir = PathBuf::from(&out_dir).join("tmp");
if !temp_dir.exists() {
fs::create_dir_all(&temp_dir)?;
}
let zip_path = temp_dir.join(zip_filename);
download_file(&download_url, &zip_path)?;
extract_library(&zip_path, &lib_path, &target_dir)?;
fs::remove_file(zip_path)?;
fs::remove_dir_all(temp_dir)?;
}
Ok(())
}
fn get_target_lib_dir(out_dir: &str) -> PathBuf {
let mut path = PathBuf::from(out_dir);
path.extend(&["libs"]);
cfg_if::cfg_if! {
if #[cfg(all(target_arch="x86_64", target_os="macos"))] {
path.extend(&["darwin-x86_64"]);
} else if #[cfg(all(target_arch="aarch64", target_os="macos"))] {
path.extend(&["darwin-aarch64"]);
} else if #[cfg(all(target_arch="aarch64", target_os="linux", target_env="gnu"))] {
path.extend(&["linux-aarch64"]);
} else if #[cfg(all(target_arch="x86_64", target_os="linux", target_env="gnu"))] {
path.extend(&["linux-x86_64"]);
} else if #[cfg(all(target_arch="x86", target_os="linux", target_env="gnu"))] {
path.extend(&["linux-x86"]);
} else if #[cfg(all(target_arch="x86_64", target_os="linux", target_env="musl"))] {
path.extend(&["musl-x86_64"]);
} else if #[cfg(all(target_arch="aarch64", target_os="linux", target_env="musl"))] {
path.extend(&["musl-aarch64"]);
} else if #[cfg(all(target_arch="x86_64", target_os="windows", target_env="msvc"))] {
path.extend(&["win32-x86_64"]);
} else if #[cfg(all(target_arch="x86", target_os="windows", target_env="msvc"))] {
path.extend(&["win32-x86"]);
}
}
path
}
fn download_file(url: &str, path: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
let response = ureq::get(url).call()?;
let mut file = fs::File::create(path)?;
io::copy(&mut response.into_reader(), &mut file)?;
Ok(())
}
fn extract_library(zip_path: &PathBuf, lib_path: &str, target_dir: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
let file = fs::File::open(zip_path)?;
let mut archive = zip::ZipArchive::new(file)?;
for i in 0..archive.len() {
let mut file = archive.by_index(i)?;
let name = file.name();
if name.ends_with(lib_path) {
let filename = std::path::Path::new(name).file_name().unwrap();
let outpath = target_dir.join(filename);
let mut outfile = fs::File::create(&outpath)?;
io::copy(&mut file, &mut outfile)?;
break;
}
}
Ok(())
}
fn set_lib_search_dir() -> () {
let out_dir: String = env::var("OUT_DIR").unwrap();
fn print_link_search_path(base_dir: String, extension_path: &[&str]) {
let mut path = PathBuf::from(base_dir.clone());
path.extend(extension_path);
println!("cargo:rustc-link-search=native={}", path.display());
}
cfg_if::cfg_if! {
if #[cfg(all(target_arch="x86_64", target_os="macos"))] {
print_link_search_path(out_dir, &["libs", "darwin-x86_64"]);
} else if #[cfg(all(target_arch="aarch64", target_os="macos"))] {
print_link_search_path(out_dir, &["libs", "darwin-aarch64"]);
} else if #[cfg(all(target_arch="aarch64", target_os="linux", target_env="gnu"))] {
print_link_search_path(out_dir, &["libs", "linux-aarch64"]);
} else if #[cfg(all(target_arch="x86_64", target_os="linux", target_env="gnu"))] {
print_link_search_path(out_dir, &["libs", "linux-x86_64"]);
} else if #[cfg(all(target_arch="x86", target_os="linux", target_env="gnu"))] {
print_link_search_path(out_dir, &["libs", "linux-x86"]);
} else if #[cfg(all(target_arch="x86_64", target_os="linux", target_env="musl"))] {
print_link_search_path(out_dir, &["libs", "musl-x86_64"]);
} else if #[cfg(all(target_arch="aarch64", target_os="linux", target_env="musl"))] {
print_link_search_path(out_dir, &["libs", "musl-aarch64"]);
} else if #[cfg(all(target_arch="x86_64", target_os="windows", target_env="msvc"))] {
print_link_search_path(out_dir, &["libs", "win32-x86_64"]);
} else if #[cfg(all(target_arch="x86", target_os="windows", target_env="msvc"))] {
print_link_search_path(out_dir, &["libs", "win32-x86"]);
} else {
compile_error!("The build target is not supported by LexActivator.");
}
}
println!("cargo:rustc-link-lib=LexActivator");
}
fn set_libs_to_link() {
cfg_if::cfg_if! {
if #[cfg(target_os="macos")] {
println!("cargo:rustc-link-lib=dylib=c++");
let output = Command::new("sh")
.arg("-c")
.arg("clang --print-search-dirs | grep -E 'libraries' | cut -d'=' -f2")
.output()
.expect("LexActivator failed to find clang libraries. Please ensure that clang is installed.");
let path = String::from_utf8_lossy(&output.stdout);
let clang_libs_path = format!("{}/lib/darwin/", path.trim());
println!("cargo:rustc-link-search=native={}", clang_libs_path);
println!("cargo:rustc-link-lib=static=clang_rt.osx");
println!("cargo:rustc-link-lib=framework=Security");
println!("cargo:rustc-link-lib=framework=CoreFoundation");
println!("cargo:rustc-link-lib=framework=SystemConfiguration");
} else if #[cfg(target_os="linux")] {
println!("cargo:rustc-link-lib=dylib=stdc++");
} else if #[cfg(target_os="windows")] {
}
}
}
fn main() {
if let Err(e) = download_and_setup_libs() {
eprintln!("Failed to download libraries: {}", e);
std::process::exit(1);
}
set_lib_search_dir();
set_libs_to_link();
}