#[macro_use]
extern crate unwrap;
#[cfg(not(feature = "get-libsodium"))]
extern crate pkg_config;
const VERSION: &'static str = "1.0.11";
#[cfg(not(feature = "get-libsodium"))]
fn main() {
use std::env;
if let Ok(lib_dir) = env::var("SODIUM_LIB_DIR") {
println!("cargo:rustc-flags=-L native={}", lib_dir);
let mode = match env::var_os("SODIUM_STATIC") {
Some(_) => "static",
None => "dylib",
};
println!("cargo:rustc-flags=-l {0}=sodium", mode);
println!("cargo:warning=Using unknown libsodium version. This crate is tested against \
{} and may not be fully compatible with other versions.",
VERSION);
} else {
let lib_details = unwrap!(pkg_config::probe_library("libsodium"));
if lib_details.version != VERSION {
println!("cargo:warning=Using libsodium version {}. This crate is tested against {} \
and may not be fully compatible with {}.",
lib_details.version,
VERSION,
lib_details.version);
}
}
}
#[cfg(feature = "get-libsodium")]
extern crate gcc;
#[cfg(feature = "get-libsodium")]
extern crate flate2;
#[cfg(feature = "get-libsodium")]
extern crate tar;
#[cfg(feature = "get-libsodium")]
fn get_install_dir() -> String {
use std::env;
unwrap!(env::var("OUT_DIR")) + "/installed"
}
#[cfg(all(windows, feature = "get-libsodium"))]
fn main() {
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::process::Command;
use flate2::read::GzDecoder;
use tar::Archive;
if cfg!(target_env = "msvc") {
panic!("This feature currently can't be used with MSVC builds.");
}
let basename = "libsodium-".to_string() + VERSION;
let gz_filename = basename.clone() + "-mingw.tar.gz";
let url = "https://download.libsodium.org/libsodium/releases/".to_string() + &gz_filename;
let install_dir = get_install_dir();
let gz_path = install_dir.clone() + "/" + &gz_filename;
unwrap!(fs::create_dir_all(Path::new(&install_dir).join("lib")));
let command = "([Net.ServicePointManager]::SecurityProtocol = 'Tls12') -and \
((New-Object System.Net.WebClient).DownloadFile(\""
.to_string() + &url + "\", \"" + &gz_path + "\"))";
let mut download_cmd = Command::new("powershell");
let 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));
}
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 {
Path::new(&install_dir).join("lib").join("libsodium.a")
} else {
continue;
};
let _ = unwrap!(entry.unpack(full_install_path));
}
let _ = fs::remove_file(gz_path);
let mut lib_search_dirs = vec![Path::new(&install_dir).join("lib")];
let mut where_cmd = Command::new("where");
let where_output = where_cmd.arg(gcc::Config::new().get_compiler().path())
.output()
.unwrap_or_else(|error| {
panic!("Failed to run where command: {}", error);
});
if !where_output.status.success() {
panic!("\n{:?}\n{}\n{}\n",
where_cmd,
String::from_utf8_lossy(&where_output.stdout),
String::from_utf8_lossy(&where_output.stderr));
}
let compiler_path_as_string = String::from_utf8_lossy(&where_output.stdout);
let compiler_path = PathBuf::from(unwrap!(compiler_path_as_string.lines().next()).trim());
let mingw_path = unwrap!(unwrap!(compiler_path.parent()).parent());
if cfg!(target_pointer_width = "32") {
lib_search_dirs.push(mingw_path.join("lib"));
lib_search_dirs.push(mingw_path.join("i686-w64-mingw32").join("lib"));
} else {
lib_search_dirs.push(mingw_path.join("x86_64-w64-mingw32").join("lib"));
}
println!("cargo:rustc-link-lib=static=sodium");
println!("cargo:rustc-link-lib=pthread");
for lib_search_dir in &lib_search_dirs {
println!("cargo:rustc-link-search=native={}",
lib_search_dir.display());
}
println!("cargo:include={}/include", install_dir);
}
#[cfg(all(not(windows), feature = "get-libsodium"))]
fn main() {
use std::env;
use std::fs::{self, File};
use std::process::Command;
use flate2::read::GzDecoder;
use tar::Archive;
let basename = "libsodium-".to_string() + VERSION;
let gz_filename = basename.clone() + ".tar.gz";
let url = "https://github.com/jedisct1/libsodium/releases/download/".to_string() + VERSION +
"/" + &gz_filename;
let mut install_dir = get_install_dir();
let mut source_dir = unwrap!(env::var("OUT_DIR")) + "/source";
let target = unwrap!(env::var("TARGET"));
if install_dir.contains(" ") {
let fallback_path = "/tmp/".to_string() + &basename + "/" + ⌖
install_dir = fallback_path.clone() + "/installed";
source_dir = fallback_path.clone() + "/source";
println!("cargo:warning=The path to the usual build directory contains spaces and hence \
can't be used to build libsodium. Falling back to use {}. If running `cargo \
clean`, ensure you also delete this fallback directory",
fallback_path);
}
let gz_path = source_dir.clone() + "/" + &gz_filename;
unwrap!(fs::create_dir_all(&install_dir));
unwrap!(fs::create_dir_all(&source_dir));
let mut curl_cmd = Command::new("curl");
let curl_output = curl_cmd.arg(&url)
.arg("-sSLvo")
.arg(&gz_path)
.output()
.unwrap_or_else(|error| {
panic!("Failed to run curl command: {}", error);
});
if !curl_output.status.success() {
panic!("\n{:?}\n{}\n{}\n",
curl_cmd,
String::from_utf8_lossy(&curl_output.stdout),
String::from_utf8_lossy(&curl_output.stderr));
}
let gz_archive = unwrap!(File::open(&gz_path));
let gz_decoder = unwrap!(GzDecoder::new(gz_archive));
let mut archive = Archive::new(gz_decoder);
unwrap!(archive.unpack(&source_dir));
source_dir.push_str(&format!("/{}", basename));
let _ = fs::remove_file(gz_path);
let gcc = gcc::Config::new();
let (cc, cflags) = if target.contains("i686") {
(format!("{} -m32", gcc.get_compiler().path().display()),
env::var("CFLAGS").unwrap_or(String::default()) + " -march=i686")
} else {
(format!("{}", gcc.get_compiler().path().display()),
env::var("CFLAGS").unwrap_or(String::default()))
};
let prefix_arg = format!("--prefix={}", install_dir);
let host = unwrap!(env::var("HOST"));
let host_arg = format!("--host={}", target);
let mut configure_cmd = Command::new("./configure");
let configure_output = configure_cmd.current_dir(&source_dir)
.env("CC", &cc)
.env("CFLAGS", &cflags)
.arg(&prefix_arg)
.arg(&host_arg)
.arg("--enable-shared=no")
.arg("--disable-pie")
.output()
.unwrap_or_else(|error| {
panic!("Failed to run './configure': {}", error);
});
if !configure_output.status.success() {
panic!("\n{:?}\nCFLAGS={}\nCC={}\n{}\n{}\n",
configure_cmd,
cflags,
cc,
String::from_utf8_lossy(&configure_output.stdout),
String::from_utf8_lossy(&configure_output.stderr));
}
let j_arg = format!("-j{}", unwrap!(env::var("NUM_JOBS")));
let cross_compiling = target != host;
let make_arg = if cross_compiling { "all" } else { "check" };
let mut make_cmd = Command::new("make");
let make_output = make_cmd.current_dir(&source_dir)
.env("CC", &cc)
.env("CFLAGS", &cflags)
.env("V", "1")
.arg(make_arg)
.arg(&j_arg)
.output()
.unwrap_or_else(|error| {
panic!("Failed to run 'make check': {}", error);
});
if !make_output.status.success() {
let need_i386 = if cross_compiling &&
String::from_utf8_lossy(&make_output.stderr)
.contains("fatal error: asm/errno.h: No such file or directory") {
"********************************************\nPossible missing dependencies. Try \
running:\n sudo apt-get install \
linux-libc-dev:i386\n********************************************\n\n"
} else {
""
};
panic!("\n{:?}\nCFLAGS={}\nCC={}\n{}\n{}\n{}\n{}",
make_cmd,
&cflags,
&cc,
String::from_utf8_lossy(&configure_output.stdout),
String::from_utf8_lossy(&make_output.stdout),
String::from_utf8_lossy(&make_output.stderr),
need_i386);
}
let mut install_cmd = Command::new("make");
let install_output = install_cmd.current_dir(&source_dir)
.env("CC", &cc)
.env("CFLAGS", &cflags)
.arg("install")
.output()
.unwrap_or_else(|error| {
panic!("Failed to run 'make install': {}", error);
});
if !install_output.status.success() {
panic!("\n{:?}\n{}\n{}\n{}\n{}\n",
install_cmd,
String::from_utf8_lossy(&configure_output.stdout),
String::from_utf8_lossy(&make_output.stdout),
String::from_utf8_lossy(&install_output.stdout),
String::from_utf8_lossy(&install_output.stderr));
}
println!("cargo:rustc-link-lib=static=sodium");
println!("cargo:rustc-link-search=native={}/lib", install_dir);
println!("cargo:include={}/include", install_dir);
}