2022-02-23 07:12:51 -05:00
|
|
|
use std::env;
|
|
|
|
use std::fs;
|
|
|
|
use std::path::{Path, PathBuf};
|
|
|
|
|
|
|
|
pub struct Build {
|
|
|
|
out_dir: Option<PathBuf>,
|
|
|
|
target: Option<String>,
|
|
|
|
host: Option<String>,
|
2023-05-20 18:07:39 -04:00
|
|
|
// Max number of Lua stack slots that a C function can use
|
|
|
|
max_cstack_size: usize,
|
|
|
|
// Use longjmp instead of C++ exceptions
|
|
|
|
use_longjmp: bool,
|
2023-05-20 17:49:37 -04:00
|
|
|
// Enable code generator (jit)
|
|
|
|
enable_codegen: bool,
|
2022-02-23 07:12:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Artifacts {
|
|
|
|
include_dir: PathBuf,
|
|
|
|
lib_dir: PathBuf,
|
|
|
|
libs: Vec<String>,
|
|
|
|
cpp_stdlib: Option<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("luau-build")),
|
|
|
|
target: env::var("TARGET").ok(),
|
|
|
|
host: env::var("HOST").ok(),
|
2023-05-20 18:07:39 -04:00
|
|
|
max_cstack_size: 100000,
|
|
|
|
use_longjmp: false,
|
2023-05-20 17:49:37 -04:00
|
|
|
enable_codegen: false,
|
2022-02-23 07:12:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-05-20 18:07:39 -04:00
|
|
|
pub fn set_max_cstack_size(&mut self, size: usize) -> &mut Build {
|
|
|
|
self.max_cstack_size = size;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn use_longjmp(&mut self, r#use: bool) -> &mut Build {
|
|
|
|
self.use_longjmp = r#use;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2023-05-20 17:49:37 -04:00
|
|
|
pub fn enable_codegen(&mut self, enable: bool) -> &mut Build {
|
|
|
|
self.enable_codegen = enable;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2022-02-23 07:12:51 -05:00
|
|
|
pub fn build(&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");
|
|
|
|
let lib_dir = out_dir.join("lib");
|
|
|
|
let include_dir = out_dir.join("include");
|
|
|
|
|
|
|
|
let source_dir_base = Path::new(env!("CARGO_MANIFEST_DIR"));
|
2022-05-28 05:50:18 -04:00
|
|
|
let common_include_dir = source_dir_base.join("luau").join("Common").join("include");
|
2022-02-23 07:12:51 -05:00
|
|
|
let ast_source_dir = source_dir_base.join("luau").join("Ast").join("src");
|
|
|
|
let ast_include_dir = source_dir_base.join("luau").join("Ast").join("include");
|
2023-05-20 17:49:37 -04:00
|
|
|
let codegen_source_dir = source_dir_base.join("luau").join("CodeGen").join("src");
|
|
|
|
let codegen_include_dir = source_dir_base.join("luau").join("CodeGen").join("include");
|
2022-02-23 07:12:51 -05:00
|
|
|
let compiler_source_dir = source_dir_base.join("luau").join("Compiler").join("src");
|
|
|
|
let compiler_include_dir = source_dir_base
|
|
|
|
.join("luau")
|
|
|
|
.join("Compiler")
|
|
|
|
.join("include");
|
|
|
|
let vm_source_dir = source_dir_base.join("luau").join("VM").join("src");
|
|
|
|
let vm_include_dir = source_dir_base.join("luau").join("VM").join("include");
|
|
|
|
|
|
|
|
// Cleanup
|
|
|
|
if lib_dir.exists() {
|
|
|
|
fs::remove_dir_all(&lib_dir).unwrap();
|
|
|
|
}
|
|
|
|
fs::create_dir_all(&lib_dir).unwrap();
|
|
|
|
|
|
|
|
if include_dir.exists() {
|
|
|
|
fs::remove_dir_all(&include_dir).unwrap();
|
|
|
|
}
|
|
|
|
fs::create_dir_all(&include_dir).unwrap();
|
|
|
|
|
|
|
|
// Configure C++
|
|
|
|
let mut config = cc::Build::new();
|
|
|
|
config
|
|
|
|
.target(target)
|
|
|
|
.host(host)
|
|
|
|
.warnings(false)
|
|
|
|
.cargo_metadata(false)
|
|
|
|
.flag_if_supported("-std=c++17")
|
|
|
|
.flag_if_supported("/std:c++17") // MSVC
|
|
|
|
.cpp(true);
|
|
|
|
|
2023-05-20 18:07:39 -04:00
|
|
|
// Common defines
|
|
|
|
config.define("LUAI_MAXCSTACK", &*self.max_cstack_size.to_string());
|
|
|
|
|
|
|
|
if self.use_longjmp {
|
|
|
|
config.define("LUA_USE_LONGJMP", "1");
|
|
|
|
}
|
|
|
|
|
2023-05-20 17:49:37 -04:00
|
|
|
if self.enable_codegen {
|
|
|
|
config.define("LUA_CUSTOM_EXECUTION", None);
|
|
|
|
}
|
|
|
|
|
2022-02-23 07:12:51 -05:00
|
|
|
if cfg!(not(debug_assertions)) {
|
|
|
|
config.define("NDEBUG", None);
|
2022-08-23 05:45:55 -04:00
|
|
|
config.opt_level(2);
|
2023-05-14 15:20:47 -04:00
|
|
|
// this flag allows compiler to lower sqrt() into a single CPU instruction
|
|
|
|
config.flag_if_supported("-fno-math-errno");
|
2022-02-23 07:12:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Build Ast
|
|
|
|
let ast_lib_name = "luauast";
|
|
|
|
config
|
|
|
|
.clone()
|
|
|
|
.include(&ast_include_dir)
|
2022-05-28 05:50:18 -04:00
|
|
|
.include(&common_include_dir)
|
2022-02-23 07:12:51 -05:00
|
|
|
.add_files_by_ext(&ast_source_dir, "cpp")
|
|
|
|
.out_dir(&lib_dir)
|
|
|
|
.compile(ast_lib_name);
|
|
|
|
|
2023-05-20 17:49:37 -04:00
|
|
|
// Build CogeGen
|
|
|
|
let codegen_lib_name = "luaucodegen";
|
|
|
|
if self.enable_codegen {
|
|
|
|
config
|
|
|
|
.clone()
|
|
|
|
.include(&codegen_include_dir)
|
|
|
|
.include(&common_include_dir)
|
|
|
|
.include(&vm_include_dir)
|
|
|
|
.include(&vm_source_dir)
|
|
|
|
.define("LUACODEGEN_API", "extern \"C\"")
|
|
|
|
// Code generator uses lua VM internals, so we need to provide the same defines used to build VM
|
|
|
|
.define("LUA_API", "extern \"C\"")
|
|
|
|
.add_files_by_ext(&codegen_source_dir, "cpp")
|
|
|
|
.out_dir(&lib_dir)
|
|
|
|
.compile(codegen_lib_name);
|
|
|
|
}
|
|
|
|
|
2022-02-23 07:12:51 -05:00
|
|
|
// Build Compiler
|
|
|
|
let compiler_lib_name = "luaucompiler";
|
|
|
|
config
|
|
|
|
.clone()
|
|
|
|
.include(&compiler_include_dir)
|
|
|
|
.include(&ast_include_dir)
|
2022-05-28 05:50:18 -04:00
|
|
|
.include(&common_include_dir)
|
2022-02-23 07:12:51 -05:00
|
|
|
.define("LUACODE_API", "extern \"C\"")
|
|
|
|
.add_files_by_ext(&compiler_source_dir, "cpp")
|
|
|
|
.out_dir(&lib_dir)
|
|
|
|
.compile(compiler_lib_name);
|
|
|
|
|
|
|
|
// Build VM
|
|
|
|
let vm_lib_name = "luauvm";
|
|
|
|
config
|
|
|
|
.clone()
|
|
|
|
.include(&vm_include_dir)
|
2022-05-28 05:50:18 -04:00
|
|
|
.include(&common_include_dir)
|
2022-02-23 07:12:51 -05:00
|
|
|
.define("LUA_API", "extern \"C\"")
|
|
|
|
.add_files_by_ext(&vm_source_dir, "cpp")
|
|
|
|
.out_dir(&lib_dir)
|
|
|
|
.compile(vm_lib_name);
|
|
|
|
|
|
|
|
for f in &["lua.h", "luaconf.h", "lualib.h"] {
|
|
|
|
fs::copy(vm_include_dir.join(f), include_dir.join(f)).unwrap();
|
|
|
|
}
|
|
|
|
for f in &["luacode.h"] {
|
|
|
|
fs::copy(compiler_include_dir.join(f), include_dir.join(f)).unwrap();
|
|
|
|
}
|
|
|
|
|
2023-05-20 17:49:37 -04:00
|
|
|
let mut artifacts = Artifacts {
|
2022-02-23 07:12:51 -05:00
|
|
|
lib_dir,
|
|
|
|
include_dir,
|
|
|
|
libs: vec![
|
|
|
|
ast_lib_name.to_string(),
|
|
|
|
compiler_lib_name.to_string(),
|
|
|
|
vm_lib_name.to_string(),
|
|
|
|
],
|
|
|
|
cpp_stdlib: Self::get_cpp_link_stdlib(target),
|
2023-05-20 17:49:37 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
if self.enable_codegen {
|
|
|
|
artifacts.libs.push(codegen_lib_name.to_string());
|
2022-02-23 07:12:51 -05:00
|
|
|
}
|
2023-05-20 17:49:37 -04:00
|
|
|
|
|
|
|
artifacts
|
2022-02-23 07:12:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn get_cpp_link_stdlib(target: &str) -> Option<String> {
|
|
|
|
// Copied from the `cc` crate
|
|
|
|
if target.contains("msvc") {
|
|
|
|
None
|
|
|
|
} else if target.contains("apple") {
|
|
|
|
Some("c++".to_string())
|
|
|
|
} else if target.contains("freebsd") {
|
|
|
|
Some("c++".to_string())
|
|
|
|
} else if target.contains("openbsd") {
|
|
|
|
Some("c++".to_string())
|
|
|
|
} else if target.contains("android") {
|
|
|
|
Some("c++_shared".to_string())
|
|
|
|
} else {
|
|
|
|
Some("stdc++".to_string())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
if let Some(ref cpp_stdlib) = self.cpp_stdlib {
|
|
|
|
println!("cargo:rustc-link-lib={}", cpp_stdlib);
|
|
|
|
}
|
2022-12-02 18:00:38 -05:00
|
|
|
if let Some(version) = self.version() {
|
|
|
|
println!("cargo:rustc-env=LUAU_VERSION={}", version);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn version(&self) -> Option<String> {
|
|
|
|
let pkg_version = env!("CARGO_PKG_VERSION");
|
|
|
|
let (_, luau_version) = pkg_version.split_once("+luau")?;
|
|
|
|
Some(format!("0.{luau_version}"))
|
2022-02-23 07:12:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trait AddFilesByExt {
|
|
|
|
fn add_files_by_ext(&mut self, dir: &Path, ext: &str) -> &mut Self;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AddFilesByExt for cc::Build {
|
|
|
|
fn add_files_by_ext(&mut self, dir: &Path, ext: &str) -> &mut Self {
|
|
|
|
for entry in fs::read_dir(dir)
|
|
|
|
.unwrap()
|
|
|
|
.filter_map(|e| e.ok())
|
|
|
|
.filter(|e| e.path().extension() == Some(ext.as_ref()))
|
|
|
|
{
|
|
|
|
self.file(entry.path());
|
|
|
|
}
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|