extern crate cc;
#[cfg(windows)]
extern crate flate2;
extern crate pkg_config;
#[macro_use]
extern crate unwrap;
#[cfg(windows)]
extern crate libc;
#[cfg(windows)]
extern crate tar;
#[cfg(windows)]
extern crate vcpkg;
#[cfg(windows)]
extern crate zip;
use std::env;
#[cfg(unix)]
use std::process::{Command, Stdio};
const VERSION: &'static str = "1.0.16";
fn main() {
println!("cargo:rerun-if-env-changed=SODIUM_LIB_DIR");
println!("cargo:rerun-if-env-changed=SODIUM_STATIC");
println!("cargo:rerun-if-env-changed=SODIUM_BUILD_STATIC");
if probe_libsodium_vcpkg() {
return;
}
if let Ok(lib_dir) = env::var("SODIUM_LIB_DIR") {
println!("cargo:rustc-link-search=native={}", lib_dir);
let mode = match env::var_os("SODIUM_STATIC") {
Some(_) => "static",
None => "dylib",
};
println!("cargo:rustc-link-lib={0}=sodium", mode);
return;
}
if let None = env::var_os("SODIUM_BUILD_STATIC") {
match pkg_config::find_library("libsodium") {
Ok(..) => return,
Err(..) => panic!(
"Missing libsodium library in your system, \
try to use SODIUM_BUILD_STATIC=yes to build it from source"
),
}
}
println!("Building libsodium {} from source", VERSION);
build();
}
#[cfg(windows)]
fn probe_libsodium_vcpkg() -> bool {
vcpkg::probe_package("libsodium").is_ok()
}
#[cfg(not(windows))]
fn probe_libsodium_vcpkg() -> bool {
false
}
#[cfg(windows)]
fn get_install_dir() -> String {
use std::env;
unwrap!(env::var("OUT_DIR")) + "/installed"
}
#[cfg(windows)]
fn check_powershell_version() {
let mut check_ps_version_cmd = ::std::process::Command::new("powershell");
let check_ps_version_output = check_ps_version_cmd
.arg("-Command")
.arg("If ($PSVersionTable.PSVersion.Major -lt 4) { exit 1 }")
.output()
.unwrap_or_else(|error| {
panic!("Failed to run powershell command: {}", error);
});
if !check_ps_version_output.status.success() {
panic!(
"\n{:?}\n{}\n{}\nYou must have Powershell v4.0 or greater installed.\n\n",
check_ps_version_cmd,
String::from_utf8_lossy(&check_ps_version_output.stdout),
String::from_utf8_lossy(&check_ps_version_output.stderr)
);
}
}
#[cfg(windows)]
fn download_compressed_file() -> String {
use std::process::Command;
let basename = "libsodium-".to_string() + VERSION;
let zip_filename = if cfg!(target_env = "msvc") {
basename.clone() + "-msvc.zip"
} else {
basename.clone() + "-mingw.tar.gz"
};
let url = "https://download.libsodium.org/libsodium/releases/".to_string() + &zip_filename;
let zip_path = get_install_dir() + "/" + &zip_filename;
let mut command = "([Net.ServicePointManager]::SecurityProtocol = 'Tls12') -and \
((New-Object System.Net.WebClient).DownloadFile(\""
.to_string() + &url + "\", \"" + &zip_path + "\"))";
let mut download_cmd = Command::new("powershell");
let mut download_output = download_cmd
.arg("-Command")
.arg(&command)
.output()
.unwrap_or_else(|error| {
panic!("Failed to run powershell download command: {}", error);
});
if download_output.status.success() {
return zip_path;
}
let fallback_url = "https://raw.githubusercontent.com/maidsafe/QA/master/appveyor/".to_string()
+ &zip_filename;
println!(
"cargo:warning=Failed to download libsodium from {}. Falling back to MaidSafe mirror \
at {}",
url, fallback_url
);
command = "([Net.ServicePointManager]::SecurityProtocol = 'Tls12') -and \
((New-Object System.Net.WebClient).DownloadFile(\""
.to_string() + &fallback_url + "\", \"" + &zip_path + "\"))";
download_cmd = Command::new("powershell");
download_output = download_cmd
.arg("-Command")
.arg(&command)
.output()
.unwrap_or_else(|error| {
panic!("Failed to run powershell download command: {}", error);
});
if !download_output.status.success() {
panic!(
"\n{:?}\n{}\n{}\n",
download_cmd,
String::from_utf8_lossy(&download_output.stdout),
String::from_utf8_lossy(&download_output.stderr)
);
}
zip_path
}
#[cfg(all(windows, target_env = "msvc"))]
fn build() {
use libc::S_IFDIR;
use std::fs::{self, File};
use std::io::{Read, Write};
use std::path::Path;
use zip::ZipArchive;
check_powershell_version();
let install_dir = get_install_dir();
let lib_install_dir = Path::new(&install_dir).join("lib");
unwrap!(fs::create_dir_all(&lib_install_dir));
let zip_path = download_compressed_file();
let zip_file = unwrap!(File::open(&zip_path));
let mut zip_archive = unwrap!(ZipArchive::new(zip_file));
let arch_path = if cfg!(target_pointer_width = "32") {
Path::new("Win32")
} else if cfg!(target_pointer_width = "64") {
Path::new("x64")
} else {
panic!("target_pointer_width not 32 or 64")
};
let unpacked_lib = arch_path.join("Release/v140/static/libsodium.lib");
for i in 0..zip_archive.len() {
let mut entry = unwrap!(zip_archive.by_index(i));
let entry_name = entry.name().to_string();
let entry_path = Path::new(&entry_name);
let opt_install_path = if entry_path.starts_with("include") {
let is_dir = (unwrap!(entry.unix_mode()) & S_IFDIR as u32) != 0;
if is_dir {
let _ = fs::create_dir(&Path::new(&install_dir).join(entry_path));
None
} else {
Some(Path::new(&install_dir).join(entry_path))
}
} else if entry_path == unpacked_lib {
Some(lib_install_dir.join("libsodium.lib"))
} else {
None
};
if let Some(full_install_path) = opt_install_path {
let mut buffer = Vec::with_capacity(entry.size() as usize);
assert_eq!(entry.size(), unwrap!(entry.read_to_end(&mut buffer)) as u64);
let mut file = unwrap!(File::create(&full_install_path));
unwrap!(file.write_all(&buffer));
}
}
let _ = fs::remove_file(zip_path);
println!("cargo:rustc-link-lib=static=libsodium");
println!(
"cargo:rustc-link-search=native={}",
lib_install_dir.display()
);
println!("cargo:include={}/include", install_dir);
}
#[cfg(all(windows, not(target_env = "msvc")))]
fn build() {
use flate2::read::GzDecoder;
use std::fs::{self, File};
use std::path::Path;
use tar::Archive;
check_powershell_version();
let install_dir = get_install_dir();
let lib_install_dir = Path::new(&install_dir).join("lib");
unwrap!(fs::create_dir_all(&lib_install_dir));
let gz_path = download_compressed_file();
let gz_archive = unwrap!(File::open(&gz_path));
let gz_decoder = unwrap!(GzDecoder::new(gz_archive));
let mut archive = Archive::new(gz_decoder);
let arch_path = if cfg!(target_pointer_width = "32") {
Path::new("libsodium-win32")
} else if cfg!(target_pointer_width = "64") {
Path::new("libsodium-win64")
} else {
panic!("target_pointer_width not 32 or 64")
};
let unpacked_include = arch_path.join("include");
let unpacked_lib = arch_path.join("lib\\libsodium.a");
let entries = unwrap!(archive.entries());
for entry_result in entries {
let mut entry = unwrap!(entry_result);
let entry_path = unwrap!(entry.path()).to_path_buf();
let full_install_path = if entry_path.starts_with(&unpacked_include) {
let include_file = unwrap!(entry_path.strip_prefix(arch_path));
Path::new(&install_dir).join(include_file)
} else if entry_path == unpacked_lib {
lib_install_dir.join("libsodium.a")
} else {
continue;
};
unwrap!(entry.unpack(full_install_path));
}
let _ = fs::remove_file(gz_path);
println!("cargo:rustc-link-lib=static=sodium");
println!(
"cargo:rustc-link-search=native={}",
lib_install_dir.display()
);
println!("cargo:include={}/include", install_dir);
}
#[cfg(unix)]
fn build() {
use std::fs;
use std::path::Path;
let cargo_dir = unwrap!(env::var("CARGO_MANIFEST_DIR"));
let output_dir = unwrap!(env::var("OUT_DIR"));
let src = Path::new(&cargo_dir[..]);
let dst = Path::new(&output_dir[..]);
let target = unwrap!(env::var("TARGET"));
let root = src.join("libsodium");
let mut autogen_cmd = Command::new("sh");
autogen_cmd.arg("-c");
let ccmd = format!("{}", root.join("autogen.sh").display());
autogen_cmd.arg(&ccmd);
run(autogen_cmd.current_dir(&root));
let _ = fs::remove_dir_all(&dst.join("include"));
let _ = fs::remove_dir_all(&dst.join("lib"));
let build_dir = dst.join("build");
let _ = fs::remove_dir_all(&build_dir);
fs::create_dir(&build_dir).unwrap();
let mut configure_cmd = Command::new("sh");
configure_cmd.arg("-c");
let cmd_path = format!("{}", root.join("configure").display());
let dst_path = format!("{}", dst.display());
let mut ccmd = format!(
"{} --prefix={} --disable-shared --enable-static=yes",
cmd_path, dst_path
);
if target.contains("android") {
ccmd += " --disable-soname-versions";
}
configure_cmd.arg(&ccmd);
run(configure_cmd.current_dir(&build_dir));
run(Command::new(make())
.arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
.current_dir(&build_dir));
run(Command::new(make())
.arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
.arg("install")
.current_dir(&build_dir));
println!("cargo:rustc-link-lib=static=sodium");
println!("cargo:rustc-link-search=native={}/lib", dst.display());
println!("cargo:root={}", dst.display());
fn make() -> &'static str {
if cfg!(target_os = "freebsd") {
"gmake"
} else {
"make"
}
}
}
#[cfg(unix)]
fn run(cmd: &mut Command) {
println!("running: {:?}", cmd);
assert!(
unwrap!(
cmd.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.status()
).success()
);
}