242 lines
7.6 KiB
Rust
242 lines
7.6 KiB
Rust
use std::env;
|
|
use std::fs;
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::Command;
|
|
|
|
pub struct Build {
|
|
out_dir: Option<PathBuf>,
|
|
target: Option<String>,
|
|
host: Option<String>,
|
|
}
|
|
|
|
pub struct Artifacts {
|
|
include_dir: PathBuf,
|
|
lib_dir: PathBuf,
|
|
libs: Vec<String>,
|
|
}
|
|
|
|
impl Build {
|
|
#[allow(clippy::new_without_default)]
|
|
pub fn new() -> Build {
|
|
Build {
|
|
out_dir: env::var_os("OUT_DIR").map(|s| PathBuf::from(s).join("luajit-build")),
|
|
target: env::var("TARGET").ok(),
|
|
host: env::var("HOST").ok(),
|
|
}
|
|
}
|
|
|
|
pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Build {
|
|
self.out_dir = Some(path.as_ref().to_path_buf());
|
|
self
|
|
}
|
|
|
|
pub fn target(&mut self, target: &str) -> &mut Build {
|
|
self.target = Some(target.to_string());
|
|
self
|
|
}
|
|
|
|
pub fn host(&mut self, host: &str) -> &mut Build {
|
|
self.host = Some(host.to_string());
|
|
self
|
|
}
|
|
|
|
fn cmd_make(&self) -> Command {
|
|
match &self.host.as_ref().expect("HOST dir not set")[..] {
|
|
"x86_64-unknown-dragonfly" => Command::new("gmake"),
|
|
"x86_64-unknown-freebsd" => Command::new("gmake"),
|
|
_ => Command::new("make"),
|
|
}
|
|
}
|
|
|
|
pub fn build(&mut self) -> Artifacts {
|
|
let target = &self.target.as_ref().expect("TARGET not set")[..];
|
|
|
|
if target.contains("msvc") {
|
|
return self.build_msvc();
|
|
}
|
|
|
|
self.build_unix()
|
|
}
|
|
|
|
pub fn build_unix(&mut self) -> Artifacts {
|
|
let target = &self.target.as_ref().expect("TARGET not set")[..];
|
|
let host = &self.host.as_ref().expect("HOST not set")[..];
|
|
let out_dir = self.out_dir.as_ref().expect("OUT_DIR not set");
|
|
// HACK: Bazel: get path to luajit sources as defined by cargo_build_script in mlua.
|
|
let luajit2 = std::env::var("LUAJIT2").unwrap();
|
|
let source_dir = Path::new(&luajit2);
|
|
let build_dir = out_dir.join("build");
|
|
let lib_dir = out_dir.join("lib");
|
|
let include_dir = out_dir.join("include");
|
|
|
|
for dir in &[&build_dir, &lib_dir, &include_dir] {
|
|
if dir.exists() {
|
|
fs::remove_dir_all(dir)
|
|
.unwrap_or_else(|e| panic!("cannot remove {}: {}", dir.display(), e));
|
|
}
|
|
fs::create_dir_all(dir)
|
|
.unwrap_or_else(|e| panic!("cannot create {}: {}", dir.display(), e));
|
|
}
|
|
cp_r(&source_dir, &build_dir);
|
|
|
|
let mut cc = cc::Build::new();
|
|
cc.target(target).host(host).warnings(false).opt_level(2);
|
|
let compiler = cc.get_compiler();
|
|
let compiler_path = compiler.path().to_str().unwrap();
|
|
|
|
let mut make = self.cmd_make();
|
|
make.current_dir(build_dir.join("src"));
|
|
make.arg("-e");
|
|
|
|
match target {
|
|
"x86_64-apple-darwin" => {
|
|
// 10.15 causes segmentation fault on github ci
|
|
make.env("MACOSX_DEPLOYMENT_TARGET", "10.11");
|
|
}
|
|
"aarch64-apple-darwin" => {
|
|
make.env("MACOSX_DEPLOYMENT_TARGET", "11.0");
|
|
}
|
|
_ => {}
|
|
}
|
|
|
|
// Infer ar/ranlib tools from cross compilers if the it looks like
|
|
// we're doing something like `foo-gcc` route that to `foo-ranlib`
|
|
// as well.
|
|
if compiler_path.ends_with("-gcc") && !target.contains("unknown-linux-musl") {
|
|
let prefix = &compiler_path[..compiler_path.len() - 3];
|
|
make.env("CROSS", prefix);
|
|
}
|
|
|
|
// HACK: the luajit Makefile wants `uname` to decuce this, but the Bazel sandbox on Linux
|
|
// doesn't provide that. Let's assume that if we ever get to `build_unix`, we're building
|
|
// on some generic Linux for some generic Linux. This might have to be fixed if that
|
|
// assumption ever changes.
|
|
make.env("TARGET_SYS", "Linux");
|
|
make.env("HOST_SYS", "Linux");
|
|
|
|
make.env("BUILDMODE", "static");
|
|
make.env("XCFLAGS", "-fPIC");
|
|
self.run_command(make, "building LuaJIT");
|
|
|
|
for f in &["lauxlib.h", "lua.h", "luaconf.h", "luajit.h", "lualib.h"] {
|
|
fs::copy(build_dir.join("src").join(f), include_dir.join(f)).unwrap();
|
|
}
|
|
fs::copy(
|
|
build_dir.join("src").join("libluajit.a"),
|
|
lib_dir.join("libluajit-5.1.a"),
|
|
)
|
|
.unwrap();
|
|
|
|
Artifacts {
|
|
lib_dir,
|
|
include_dir,
|
|
libs: vec!["luajit-5.1".to_string()],
|
|
}
|
|
}
|
|
|
|
pub fn build_msvc(&mut self) -> Artifacts {
|
|
let target = &self.target.as_ref().expect("TARGET not set")[..];
|
|
let out_dir = self.out_dir.as_ref().expect("OUT_DIR not set");
|
|
let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("luajit2");
|
|
let build_dir = out_dir.join("build");
|
|
let lib_dir = out_dir.join("lib");
|
|
let include_dir = out_dir.join("include");
|
|
|
|
for dir in &[&build_dir, &lib_dir, &include_dir] {
|
|
if dir.exists() {
|
|
fs::remove_dir_all(dir)
|
|
.unwrap_or_else(|e| panic!("cannot remove {}: {}", dir.display(), e));
|
|
}
|
|
fs::create_dir_all(dir)
|
|
.unwrap_or_else(|e| panic!("cannot create {}: {}", dir.display(), e));
|
|
}
|
|
cp_r(&source_dir, &build_dir);
|
|
|
|
let mut msvcbuild = Command::new(build_dir.join("src").join("msvcbuild.bat"));
|
|
msvcbuild.current_dir(build_dir.join("src"));
|
|
msvcbuild.arg("static");
|
|
|
|
let cl = cc::windows_registry::find_tool(&target, "cl.exe").expect("failed to find cl");
|
|
for (k, v) in cl.env() {
|
|
msvcbuild.env(k, v);
|
|
}
|
|
|
|
self.run_command(msvcbuild, "building LuaJIT");
|
|
|
|
for f in &["lauxlib.h", "lua.h", "luaconf.h", "luajit.h", "lualib.h"] {
|
|
fs::copy(build_dir.join("src").join(f), include_dir.join(f)).unwrap();
|
|
}
|
|
fs::copy(
|
|
build_dir.join("src").join("lua51.lib"),
|
|
lib_dir.join("luajit.lib"),
|
|
)
|
|
.unwrap();
|
|
|
|
Artifacts {
|
|
lib_dir,
|
|
include_dir,
|
|
libs: vec!["luajit".to_string()],
|
|
}
|
|
}
|
|
|
|
fn run_command(&self, mut command: Command, desc: &str) {
|
|
println!("running {:?}", command);
|
|
let status = command.status().unwrap();
|
|
if !status.success() {
|
|
panic!(
|
|
"
|
|
Error {}:
|
|
Command: {:?}
|
|
Exit status: {}
|
|
",
|
|
desc, command, status
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn cp_r(src: &Path, dst: &Path) {
|
|
for f in fs::read_dir(src).expect(&format!("read_dir failed {:?}", src)) {
|
|
let f = f.expect("f read filed");
|
|
let path = f.path();
|
|
let name = path.file_name().expect("file_name failed");
|
|
|
|
// Skip git metadata
|
|
if name.to_str() == Some(".git") {
|
|
continue;
|
|
}
|
|
|
|
let dst = dst.join(name);
|
|
if f.file_type().unwrap().is_dir() {
|
|
fs::create_dir_all(&dst).unwrap();
|
|
cp_r(&path, &dst);
|
|
} else {
|
|
let _ = fs::remove_file(&dst);
|
|
fs::copy(&path, &dst).unwrap();
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Artifacts {
|
|
pub fn include_dir(&self) -> &Path {
|
|
&self.include_dir
|
|
}
|
|
|
|
pub fn lib_dir(&self) -> &Path {
|
|
&self.lib_dir
|
|
}
|
|
|
|
pub fn libs(&self) -> &[String] {
|
|
&self.libs
|
|
}
|
|
|
|
pub fn print_cargo_metadata(&self) {
|
|
println!("cargo:rustc-link-search=native={}", self.lib_dir.display());
|
|
for lib in self.libs.iter() {
|
|
println!("cargo:rustc-link-lib=static={}", lib);
|
|
}
|
|
println!("cargo:include={}", self.include_dir.display());
|
|
println!("cargo:lib={}", self.lib_dir.display());
|
|
}
|
|
}
|