Support vendored versions of Lua and LuaJIT

This commit is contained in:
Alex Orlenko 2020-01-25 19:25:55 +00:00
parent 27121c779d
commit 07fc4642ae
15 changed files with 231 additions and 300 deletions

View File

@ -9,6 +9,8 @@ readme = "README.md"
keywords = ["lua", "luajit"]
categories = ["api-bindings"]
license = "MIT"
links = "lua"
build = "build/main.rs"
description = """
High level bindings to Lua 5.1/5.2/5.3 (including LuaJIT)
with support of writing native lua modules in Rust.
@ -23,11 +25,13 @@ members = [
]
[features]
default = ["lua53"]
default = ["lua53", "lua-vendored"]
lua53 = []
lua52 = []
lua51 = []
luajit = []
lua-vendored = ["lua-src"]
luajit-vendored = ["luajit", "luajit-src"]
[dependencies]
num-traits = { version = "0.2.6" }
@ -36,6 +40,8 @@ bstr = { version = "0.2", features = ["std"], default_features = false }
[build-dependencies]
cc = { version = "1.0" }
pkg-config = { version = "0.3.11" }
lua-src = { version = "535.0.1", optional = true }
luajit-src = { version = "210.0.0", optional = true }
[dev-dependencies]
rustyline = "5.0"

189
build.rs
View File

@ -1,189 +0,0 @@
use std::env;
use std::fs::File;
use std::io::{BufRead, BufReader, Error, ErrorKind, Result};
use std::ops::Bound;
use std::path::{Path, PathBuf};
use std::process::Command;
trait CommandExt {
fn execute(&mut self) -> Result<()>;
}
impl CommandExt for Command {
/// Execute the command and return an error if it exited with a failure status.
fn execute(&mut self) -> Result<()> {
self.status()
.and_then(|status| {
if status.success() {
Ok(())
} else {
Err(Error::new(ErrorKind::Other, "non-zero exit code"))
}
})
.map_err(|_| {
Error::new(
ErrorKind::Other,
format!("The command {:?} did not run successfully.", self),
)
})
}
}
fn use_custom_lua<S: AsRef<str>>(include_dir: &S, lib_dir: &S, lua_lib: &S) -> Result<String> {
let mut version_found = String::new();
// Find LUA_VERSION_NUM
let mut lua_h_path = PathBuf::from(include_dir.as_ref());
lua_h_path.push("lua.h");
let f = File::open(lua_h_path)?;
let reader = BufReader::new(f);
for line in reader.lines() {
let line = line?;
let parts = line.split_whitespace().collect::<Vec<_>>();
if parts.len() == 3 && parts[1] == "LUA_VERSION_NUM" {
version_found = parts[2].to_string();
}
}
let mut static_link = "";
if env::var("LUA_LINK").unwrap_or(String::new()) == "static" {
static_link = "static=";
}
println!("cargo:rustc-link-search=native={}", lib_dir.as_ref());
println!("cargo:rustc-link-lib={}{}", static_link, lua_lib.as_ref());
Ok(version_found)
}
fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_paths: &[P]) {
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
// Ensure the presence of glue.rs
// if build_dir.join("glue.rs").exists() {
// return;
// }
let mut config = cc::Build::new();
for path in include_paths {
config.include(path);
}
// Compile and run glue.c
let glue = build_dir.join("glue");
config
.get_compiler()
.to_command()
.arg("src/ffi/glue/glue.c")
.arg("-o")
.arg(&glue)
.execute()
.unwrap();
Command::new(glue)
.arg(build_dir.join("glue.rs"))
.execute()
.unwrap();
}
fn main() {
let include_dir = env::var("LUA_INC").unwrap_or(String::new());
let lib_dir = env::var("LUA_LIB").unwrap_or(String::new());
let lua_lib = env::var("LUA_LIB_NAME").unwrap_or(String::new());
println!("cargo:rerun-if-env-changed=LUA_INC");
println!("cargo:rerun-if-env-changed=LUA_LIB");
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
println!("cargo:rerun-if-env-changed=LUA_LINK");
println!("cargo:rerun-if-changed=src/ffi/glue/glue.c");
if include_dir != "" && lib_dir != "" && lua_lib != "" {
let _version = use_custom_lua(&include_dir, &lib_dir, &lua_lib).unwrap();
build_glue(&[include_dir]);
return;
}
// Find lua via pkg-config
#[cfg(not(any(
feature = "lua53",
feature = "lua52",
feature = "lua51",
feature = "luajit"
)))]
panic!("You must enable one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(
feature = "lua53",
any(feature = "lua52", feature = "lua51", feature = "luajit")
))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua51", feature = "luajit"))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(feature = "lua53")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.3");
}
match lua {
Ok(lua) => build_glue(&lua.include_paths),
Err(err) => panic!(err),
};
}
#[cfg(feature = "lua52")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.2"), Bound::Excluded("5.3")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.2");
}
match lua {
Ok(lua) => build_glue(&lua.include_paths),
Err(_) => panic!("Lua 5.2 not found"),
};
}
#[cfg(feature = "lua51")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.1");
}
match lua {
Ok(lua) => build_glue(&lua.include_paths),
Err(err) => panic!(err),
};
}
#[cfg(feature = "luajit")]
{
let lua = pkg_config::Config::new()
.range_version((Bound::Included("2.0.5"), Bound::Unbounded))
.probe("luajit");
match lua {
Ok(lua) => build_glue(&lua.include_paths),
Err(err) => panic!(err),
};
}
}

106
build/find_normal.rs Normal file
View File

@ -0,0 +1,106 @@
use std::env;
use std::ffi::OsString;
use std::fs::File;
use std::io::{BufRead, BufReader, Result};
use std::ops::Bound;
use std::path::{Path, PathBuf};
pub fn probe_lua() -> PathBuf {
let include_dir = env::var_os("LUA_INC").unwrap_or(OsString::new());
let lib_dir = env::var_os("LUA_LIB").unwrap_or(OsString::new());
let lua_lib = env::var_os("LUA_LIB_NAME").unwrap_or(OsString::new());
println!("cargo:rerun-if-env-changed=LUA_INC");
println!("cargo:rerun-if-env-changed=LUA_LIB");
println!("cargo:rerun-if-env-changed=LUA_LIB_NAME");
println!("cargo:rerun-if-env-changed=LUA_LINK");
if include_dir != "" && lib_dir != "" && lua_lib != "" {
let _version = use_custom_lua(&include_dir, &lib_dir, &lua_lib).unwrap();
return PathBuf::from(include_dir);
}
// Find using via pkg-config
#[cfg(feature = "lua53")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.3"), Bound::Excluded("5.4")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.3");
}
return lua.unwrap().include_paths[0].clone();
}
#[cfg(feature = "lua52")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.2"), Bound::Excluded("5.3")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.2");
}
return lua.unwrap().include_paths[0].clone();
}
#[cfg(feature = "lua51")]
{
let mut lua = pkg_config::Config::new()
.range_version((Bound::Included("5.1"), Bound::Excluded("5.2")))
.probe("lua");
if lua.is_err() {
lua = pkg_config::Config::new().probe("lua5.1");
}
return lua.unwrap().include_paths[0].clone();
}
#[cfg(feature = "luajit")]
{
let lua = pkg_config::Config::new()
.range_version((Bound::Included("2.1.0"), Bound::Unbounded))
.probe("luajit");
return lua.unwrap().include_paths[0].clone();
}
}
fn use_custom_lua<S: AsRef<Path>>(include_dir: &S, lib_dir: &S, lua_lib: &S) -> Result<String> {
let mut version_found = String::new();
// Find LUA_VERSION_NUM
let mut lua_h_path = include_dir.as_ref().to_owned();
lua_h_path.push("lua.h");
let f = File::open(lua_h_path)?;
let reader = BufReader::new(f);
for line in reader.lines() {
let line = line?;
let parts = line.split_whitespace().collect::<Vec<_>>();
if parts.len() == 3 && parts[1] == "LUA_VERSION_NUM" {
version_found = parts[2].to_string();
}
}
let mut link_lib = String::new();
if env::var("LUA_LINK").unwrap_or(String::new()) == "static" {
link_lib = "static=".to_string();
}
println!(
"cargo:rustc-link-search=native={}",
lib_dir.as_ref().display()
);
println!(
"cargo:rustc-link-lib={}{}",
link_lib,
lua_lib.as_ref().display()
);
Ok(version_found)
}

23
build/find_vendored.rs Normal file
View File

@ -0,0 +1,23 @@
use std::path::PathBuf;
#[cfg(feature = "lua-vendored")]
use lua_src;
#[cfg(feature = "luajit-vendored")]
use luajit_src;
pub fn probe_lua() -> PathBuf {
#[cfg(all(feature = "lua53", feature = "lua-vendored"))]
let artifacts = lua_src::Build::new().build(lua_src::Lua53);
#[cfg(all(feature = "lua52", feature = "lua-vendored"))]
let artifacts = lua_src::Build::new().build(lua_src::Lua52);
#[cfg(all(feature = "lua51", feature = "lua-vendored"))]
let artifacts = lua_src::Build::new().build(lua_src::Lua51);
#[cfg(feature = "luajit-vendored")]
let artifacts = luajit_src::Build::new().build();
#[cfg(all(feature = "luajit", feature = "lua-vendored"))]
let artifacts = lua_src::Build::new().build(lua_src::Lua51); // Invalid case! Workaround to get panic
artifacts.print_cargo_metadata();
artifacts.include_dir().to_owned()
}

95
build/main.rs Normal file
View File

@ -0,0 +1,95 @@
#![allow(unreachable_code)]
use std::env;
use std::io::{Error, ErrorKind, Result};
use std::path::{Path, PathBuf};
use std::process::Command;
#[cfg_attr(
any(feature = "lua-vendored", feature = "luajit-vendored"),
path = "find_vendored.rs"
)]
#[cfg_attr(
not(any(feature = "lua-vendored", feature = "luajit-vendored")),
path = "find_normal.rs"
)]
mod find;
trait CommandExt {
fn execute(&mut self) -> Result<()>;
}
impl CommandExt for Command {
/// Execute the command and return an error if it exited with a failure status.
fn execute(&mut self) -> Result<()> {
self.status()
.and_then(|status| {
if status.success() {
Ok(())
} else {
Err(Error::new(ErrorKind::Other, "non-zero exit code"))
}
})
.map_err(|_| {
Error::new(
ErrorKind::Other,
format!("The command {:?} did not run successfully.", self),
)
})
}
}
fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_path: &P) {
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
let mut config = cc::Build::new();
config.include(include_path);
// Compile and run glue.c
let glue = build_dir.join("glue");
config
.get_compiler()
.to_command()
.arg("src/ffi/glue/glue.c")
.arg("-o")
.arg(&glue)
.execute()
.unwrap();
Command::new(glue)
.arg(build_dir.join("glue.rs"))
.execute()
.unwrap();
}
fn main() {
#[cfg(not(any(
feature = "lua53",
feature = "lua52",
feature = "lua51",
feature = "luajit"
)))]
panic!("You must enable one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(
feature = "lua53",
any(feature = "lua52", feature = "lua51", feature = "luajit")
))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua51", feature = "luajit"))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua51", feature = "luajit"))]
panic!("You can enable only one of the features: lua53, lua52, lua51, luajit");
#[cfg(all(feature = "lua-vendored", feature = "luajit"))]
panic!("You cannot mix lua-vendored and luajit features");
let include_dir = find::probe_lua();
build_glue(&include_dir);
}

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use bstr::{BStr, BString};
use mlua::{Lua, Result};

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use mlua::{Function, Lua, Result, String};
#[test]

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use std::sync::Arc;
use mlua::{Lua, Result, UserData};

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use std::cell::Cell;
use std::rc::Rc;

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use std::borrow::Cow;
use mlua::{Lua, Result, String};

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use mlua::{Lua, Nil, Result, Table, Value};
#[test]

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use std::iter::FromIterator;
use std::panic::catch_unwind;
use std::sync::Arc;

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use std::panic::catch_unwind;
use mlua::{Error, Function, Lua, Result, Thread, ThreadStatus};

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use std::os::raw::c_void;
use mlua::{Function, LightUserData, Lua, Result};

View File

@ -1,14 +1,3 @@
#![cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
feature(link_args)
)]
#[cfg_attr(
all(feature = "luajit", target_os = "macos", target_arch = "x86_64"),
link_args = "-pagezero_size 10000 -image_base 100000000"
)]
extern "system" {}
use std::sync::Arc;
use mlua::{