extern crate gcc;
use std::fs;
use std::io;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::ffi::OsString;
use std::ffi::OsStr;
trait CommandExt {
fn execute(&mut self) -> io::Result<()>;
}
impl CommandExt for Command {
fn execute(&mut self) -> io::Result<()> {
let status = try!(self.status());
if status.success() {
Ok(())
} else {
Err(io::Error::new(io::ErrorKind::Other, format!("The command\n\
\t{:?}\n\
did not run successfully.", self)))
}
}
}
fn build_lua(tooling: &gcc::Tool, source: &Path, build: &Path) -> io::Result<()> {
let platform = match env::var("TARGET").unwrap().split('-').nth(2).unwrap() {
"windows" => "mingw",
"darwin" => "macosx",
"linux" => "linux",
"freebsd" => "freebsd",
"dragonfly" => "bsd",
_ => "generic",
};
let cc = tooling.path();
let mut cflags = OsString::new();
for arg in tooling.args() {
cflags.push(arg);
cflags.push(" ");
}
let makefile = source.join("Makefile");
let make = OsString::from(format!("make -e -f {:?}", makefile.to_string_lossy().replace("\\", "/")));
let mut command = Command::new("make");
for &(ref key, ref val) in tooling.env() {
command.env(key, val);
}
command.current_dir(build)
.env("VPATH", source.to_string_lossy().replace("\\", "/"))
.env("MAKE", make)
.env("CC", cc)
.env("MYCFLAGS", cflags)
.arg("-e")
.arg("-f").arg(makefile)
.arg(platform)
.execute()
}
fn verify_msvc_environment() {
let found_cl_exe = Command::new("cl.exe").arg("/help").output().is_ok();
let found_lib_exe = Command::new("lib.exe").arg("/help").output().is_ok();
if !found_cl_exe || !found_lib_exe {
panic!("cl.exe and lib.exe must be on your %PATH% to compile Lua for MSVC.\n\
Please install this crate through the Visual Studio Native Tools Command Line.");
}
}
fn build_lua_msvc(source: &Path, build: &Path) -> io::Result<()>{
verify_msvc_environment();
let build_str = build.as_os_str().to_str().unwrap();
let mut compile_cmd = Command::new("cl.exe");
compile_cmd.current_dir(&source);
for file_res in fs::read_dir(source).unwrap() {
let dir_entry = file_res.unwrap();
let file_name = dir_entry.file_name().into_string().unwrap();
if file_name.ends_with(".c") && file_name != "luac.c" {
compile_cmd.arg(file_name);
}
}
compile_cmd.arg("/c") .arg("/MP") .arg(format!("/Fo{}\\", &build_str)) .arg("/nologo"); compile_cmd.execute().unwrap(); let mut lib_cmd = Command::new("lib.exe");
lib_cmd.current_dir(&build);
for file_res in fs::read_dir(build).unwrap() {
let dir_entry = file_res.unwrap();
let file_name = dir_entry.file_name().into_string().unwrap();
if file_name.ends_with(".obj") {
lib_cmd.arg(file_name);
}
}
lib_cmd.arg(format!("/out:{}\\lua.lib", &build_str)) .arg("/NOLOGO");
lib_cmd.execute()
}
fn prebuild() -> io::Result<()> {
let lua_dir : PathBuf = match env::var_os("LUA_LOCAL_SOURCE") {
Some(dir) => PathBuf::from(dir),
None => {
let mut dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
dir.push(OsStr::new("lua-source/src").to_str().unwrap());
dir
}
};
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let mut config = gcc::Config::new();
let msvc = env::var("TARGET").unwrap().split('-').last().unwrap() == "msvc";
println!("cargo:rustc-link-lib=static=lua");
if !msvc && lua_dir.join("liblua.a").exists() {
println!("cargo:rustc-link-search=native={}", &lua_dir.display());
} else if msvc {
if !build_dir.join("lua.lib").exists() {
try!(build_lua_msvc(&lua_dir, &build_dir));
}
println!("cargo:rustc-link-search=native={}", &build_dir.display());
} else {
if !build_dir.join("liblua.a").exists() {
let tooling = config.get_compiler();
try!(fs::create_dir_all(&build_dir));
try!(build_lua(&tooling, &lua_dir, &build_dir));
}
println!("cargo:rustc-link-search=native={}", &build_dir.display());
}
if !build_dir.join("glue.rs").exists() {
let glue = build_dir.join("glue");
try!(config.include(&lua_dir).get_compiler().to_command()
.arg("-I").arg(&lua_dir)
.arg("src/glue/glue.c")
.arg("-o").arg(&glue)
.execute());
try!(Command::new(glue)
.arg(build_dir.join("glue.rs"))
.execute());
}
Ok(())
}
fn main() {
match prebuild() {
Err(e) => panic!("Error: {}", e),
Ok(()) => (),
}
}