use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;
struct Config(HashMap<String, String>);
fn find_cfg() -> io::Result<String> {
let mut path = PathBuf::from(env::var("OUT_DIR").unwrap());
loop {
path.push("config.rust");
if path.exists() {
return Ok(path.to_str().unwrap().to_owned());
}
path.pop(); if !path.pop() {
return Err(io::Error::new(io::ErrorKind::NotFound, "No config.rust"));
}
}
}
impl Config {
fn load() -> io::Result<Config> {
let path = find_cfg()?;
let f = File::open(&path)?;
let reader = io::BufReader::new(f);
let mut map = HashMap::new();
for line in reader.lines() {
let s = line?;
if s.trim().starts_with("#") || s.trim() == "" {
continue;
}
let idx = match s.find("=") {
None => {
return Err(io::Error::new(io::ErrorKind::InvalidData, "missing ="));
}
Some(x) => x,
};
let (var, eq_val) = s.split_at(idx);
let val = &eq_val[1..];
map.insert(var.to_owned(), val.to_owned());
}
Ok(Config(map))
}
fn get(&self, key: &str) -> &str {
self.0.get(key).unwrap()
}
fn component(&self, s: &str) {
println!("cargo:rustc-link-lib=static={}", s);
}
fn dependency(&self, s: &str) {
println!("cargo:rustc-link-lib={}", s);
}
fn link_relpath(&self, s: &str) {
let builddir = self.get("BUILDDIR");
println!("cargo:rustc-link-search=native={}/{}", builddir, s);
}
fn link_path(&self, s: &str) {
println!("cargo:rustc-link-search=native={}", s);
}
fn from_cflags(&self, s: &str) {
let mut next_is_lib = false;
let mut next_is_path = false;
for ent in self.get(s).split_whitespace() {
if next_is_lib {
self.dependency(ent);
next_is_lib = false;
} else if next_is_path {
self.link_path(ent);
next_is_path = false;
} else if ent == "-l" {
next_is_lib = true;
} else if ent == "-L" {
next_is_path = true;
} else if ent.starts_with("-L") {
self.link_path(&ent[2..]);
} else if ent.starts_with("-l") {
self.dependency(&ent[2..]);
}
}
}
}
pub fn main() {
let cfg = Config::load().unwrap();
let package = env::var("CARGO_PKG_NAME").unwrap();
match package.as_ref() {
"crypto" => {
cfg.from_cflags("TOR_LDFLAGS_zlib");
cfg.from_cflags("TOR_LDFLAGS_openssl");
cfg.from_cflags("TOR_LDFLAGS_libevent");
cfg.link_relpath("src/lib");
cfg.link_relpath("src/ext/keccak-tiny");
cfg.link_relpath("src/ext/ed25519/ref10");
cfg.link_relpath("src/ext/ed25519/donna");
cfg.link_relpath("src/trunnel");
cfg.component("tor-crypt-ops-testing");
cfg.component("tor-sandbox-testing");
cfg.component("tor-encoding-testing");
cfg.component("tor-fs-testing");
cfg.component("tor-net-testing");
cfg.component("tor-buf-testing");
cfg.component("tor-time-testing");
cfg.component("tor-thread-testing");
cfg.component("tor-memarea-testing");
cfg.component("tor-log-testing");
cfg.component("tor-lock-testing");
cfg.component("tor-fdio-testing");
cfg.component("tor-container-testing");
cfg.component("tor-smartlist-core-testing");
cfg.component("tor-string-testing");
cfg.component("tor-malloc");
cfg.component("tor-wallclock");
cfg.component("tor-err-testing");
cfg.component("tor-version-testing");
cfg.component("tor-intmath-testing");
cfg.component("tor-ctime-testing");
cfg.component("curve25519_donna");
cfg.component("keccak-tiny");
cfg.component("ed25519_ref10");
cfg.component("ed25519_donna");
cfg.component("or-trunnel-testing");
cfg.from_cflags("TOR_ZLIB_LIBS");
cfg.from_cflags("TOR_LIB_MATH");
cfg.from_cflags("NSS_LIBS");
cfg.from_cflags("TOR_OPENSSL_LIBS");
cfg.from_cflags("TOR_LIBEVENT_LIBS");
cfg.from_cflags("TOR_LIB_WS32");
cfg.from_cflags("TOR_LIB_GDI");
cfg.from_cflags("TOR_LIB_USERENV");
cfg.from_cflags("CURVE25519_LIBS");
cfg.from_cflags("TOR_LZMA_LIBS");
cfg.from_cflags("TOR_ZSTD_LIBS");
cfg.from_cflags("LIBS");
}
_ => {
panic!("No configuration in build.rs for package {}", package);
}
}
}