#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
macro_rules! t {
($e:expr) => (match $e {
Ok(n) => n,
Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
})
}
fn cp_r(dir: &Path, dest: &Path) {
for entry in t!(fs::read_dir(dir)) {
let entry = t!(entry);
let path = entry.path();
let dst = dest.join(path.file_name().expect("Failed to get filename of path"));
if t!(fs::metadata(&path)).is_file() {
t!(fs::copy(path, dst));
} else {
t!(fs::create_dir_all(&dst));
cp_r(&path, &dst);
}
}
}
fn get_libsass_folder() -> PathBuf {
env::current_dir().expect("Failed to get the current directory").join("libsass")
}
#[cfg(target_os = "linux")]
fn _compile(libprobe: fn(&str) -> bool) {
if libprobe("stdc++") {
println!("cargo:rustc-link-lib=dylib=stdc++");
} else if libprobe("c++_shared") {
println!("cargo:rustc-link-lib=dylib=c++_shared");
} else if libprobe("c++") {
println!("cargo:rustc-link-lib=dylib=c++");
} else {
panic!("no c++ library found");
}
}
#[cfg(not(target_os = "linux"))]
fn _compile(libprobe: fn(&str) -> bool) {
if libprobe("c++_shared") {
println!("cargo:rustc-link-lib=dylib=c++_shared");
} else if libprobe("c++") {
println!("cargo:rustc-link-lib=dylib=c++");
} else if libprobe("stdc++") {
println!("cargo:rustc-link-lib=dylib=stdc++");
} else {
panic!("no c++ library found");
}
}
#[cfg(not(target_env = "msvc"))]
fn compile() {
let target = env::var("TARGET").expect("TARGET not found");
let src = get_libsass_folder();
let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found"));
let build = dest.join("build");
t!(fs::create_dir_all(&build));
cp_r(&src, &build);
let is_bsd = target.contains("dragonfly")
|| target.contains("freebsd")
|| target.contains("netbsd")
|| target.contains("openbsd");
let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());
let r = Command::new(if is_bsd { "gmake" } else { "make" })
.current_dir(&build)
.args(&["--jobs", &jobs])
.output()
.expect("Failed to run make/gmake. Do you have it installed?");
if !r.status.success() {
let err = String::from_utf8_lossy(&r.stderr);
let out = String::from_utf8_lossy(&r.stdout);
panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
}
println!(
"cargo:rustc-link-search=native={}",
build.join("lib").display()
);
println!("cargo:rustc-link-lib=static=sass");
let libprobe = | lib: &str | -> bool {
Command::new("cc")
.arg("-xc++")
.arg("-o/dev/null")
.arg(format!("-l{}",lib))
.arg("-shared")
.stderr(Stdio::null())
.status()
.expect("Failed to run cc. Do you have it installed?")
.success()
};
_compile(libprobe);
}
#[cfg(target_env = "msvc")]
fn compile() {
let src = get_libsass_folder();
let target = env::var("TARGET").expect("TARGET not found in environment");
let msvc_platform = if target.contains("x86_64") {
"Win64"
} else {
"Win32"
};
let dest = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR not found in environment"));
let build = dest.join("build");
t!(fs::create_dir_all(&build));
cp_r(&src, &build);
let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
if let Some(mut d) = d {
let d = d
.args(&["/upgrade", "win\\libsass.sln"])
.current_dir(&build)
.output()
.expect("Failed to run devenv. Do you have it installed?");
if !d.status.success() {
let err = String::from_utf8_lossy(&d.stderr);
let out = String::from_utf8_lossy(&d.stdout);
println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
}
}
let search = Command::new("where")
.args(&["msbuild.exe"])
.output()
.expect("Failed to run where: Could not search for msbuild.exe on path.");
let mut msbuild = if search.status.success() {
Command::new("msbuild.exe")
} else {
cc::windows_registry::find(target.as_str(), "msbuild.exe")
.expect("Could not find msbuild.exe on the registry")
};
let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or_else(|_| num_cpus::get().to_string());
let r = msbuild
.args(&[
"win\\libsass.sln",
"/p:LIBSASS_STATIC_LIB=1",
"/p:Configuration=Release",
"/p:WholeProgramOptimization=false",
"/p:UseMultiToolTask=true",
format!("/m:{}", jobs).as_str(),
format!("/p:Platform={}", msvc_platform).as_str(),
])
.current_dir(&build)
.output()
.expect("Failed to run msbuild. Do you have it installed?");
if !r.status.success() {
let err = String::from_utf8_lossy(&r.stderr);
let out = String::from_utf8_lossy(&r.stdout);
panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
}
println!(
"cargo:rustc-link-search=native={}",
build.join("win").join("bin").display()
);
println!("cargo:rustc-link-lib=static=libsass");
}
fn main() {
if pkg_config::find_library("libsass").is_ok() {
return;
}
if !get_libsass_folder().join("Makefile").exists() {
eprintln!("
Could not find libsass source
Try running `git submodule update --init` if you are building from the repository
");
std::process::exit(1);
}
compile();
}