Add build script and generated ffi

This commit is contained in:
Aaron Loucks 2019-08-15 19:13:42 -04:00
parent 50f832a25d
commit f144a4ff6a
9 changed files with 1487 additions and 0 deletions

13
Cargo.toml Normal file
View file

@ -0,0 +1,13 @@
[package]
name = "luajit-sys"
version = "0.0.1"
authors = ["Aaron Loucks <aloucks@cofront.net>"]
edition = "2018"
keywords = ["lua", "luajit", "script"]
[dependencies]
libc = "0.2"
[build-dependencies]
cc = "1.0.40"
fs_extra = "1.1.0"

26
bindgen.sh Normal file
View file

@ -0,0 +1,26 @@
#!/bin/bash
BINDGEN_VERSION=$(bindgen --version)
bindgen -o src/ffi.rs \
--raw-line "/// Generated with: ${BINDGEN_VERSION}" \
--whitelist-var "LUA.*" \
--whitelist-var "LUAJIT.*" \
--whitelist-type "lua_.*" \
--whitelist-type "luaL_.*" \
--whitelist-function "lua_.*" \
--whitelist-function "luaL_.*" \
--whitelist-function "luaJIT.*" \
--ctypes-prefix "libc" \
--use-core \
--impl-debug \
ffi.h -- -I luajit/src
sed -i -e 's/pub fn \(luaJIT_[^\(]*\)/\/\/\/ <https:\/\/luajit.org\/ext_c_api.html> \n pub fn \1/' src/ffi.rs
sed -i -e 's/pub fn \(lua_[^\(]*\)/\/\/\/ <https\:\/\/www.lua.org\/manual\/5.1\/manual.html#\1> \n pub fn \1/' src/ffi.rs
sed -i -e 's/pub fn \(luaL_[^\(]*\)/\/\/\/ <https\:\/\/www.lua.org\/manual\/5.1\/manual.html#\1> \n pub fn \1/' src/ffi.rs
sed -i -e 's/pub type \(lua_[^\=]*\)/\/\/\/ <https\:\/\/www.lua.org\/manual\/5.1\/manual.html#\1> \n pub type \1/' src/ffi.rs
sed -i -e 's/pub struct \(lua_[^\{]*\)/\/\/\/ <https\:\/\/www.lua.org\/manual\/5.1\/manual.html#\1> \n pub struct \1/' src/ffi.rs
sed -i -e 's/pub struct \(luaL_[^\{]*\)/\/\/\/ <https\:\/\/www.lua.org\/manual\/5.1\/manual.html#\1> \n pub struct \1/' src/ffi.rs
cargo +stable fmt

71
build.rs Normal file
View file

@ -0,0 +1,71 @@
use cc;
use fs_extra::dir;
use fs_extra::dir::CopyOptions;
use std::env;
use std::process::{Command, Stdio};
fn main() {
let target = env::var("TARGET").unwrap();
let luajit_dir = format!("{}\\luajit", env!("CARGO_MANIFEST_DIR"));
let out_dir = env::var("OUT_DIR").unwrap();
let src_dir = format!("{}\\luajit\\src", out_dir);
if cfg!(target_env = "msvc") {
let lib_path = format!("{}\\lua51.lib", &src_dir);
if !std::fs::metadata(&lib_path).is_ok() {
let cl_exe: cc::Tool = cc::windows_registry::find_tool(&target, "cl.exe").unwrap();
let msvsbuild_bat = format!("{}\\msvcbuild.bat", &src_dir);
let mut copy_options = CopyOptions::new();
copy_options.overwrite = true;
dir::copy(&luajit_dir, &out_dir, &copy_options).unwrap();
let mut buildcmd = Command::new(msvsbuild_bat);
for (name, value) in cl_exe.env() {
buildcmd.env(name, value);
}
buildcmd.env("Configuration", "Release");
buildcmd.args(&["static"]);
buildcmd.current_dir(&src_dir);
buildcmd.stderr(Stdio::inherit());
let mut child = buildcmd.spawn().expect("failed to run msvcbuild.bat");
if !child
.wait()
.map(|status| status.success())
.map_err(|_| false)
.unwrap_or(false)
{
panic!("Failed to build luajit");
}
}
println!("cargo:rustc-link-search=native={}", src_dir);
println!("cargo:rustc-link-lib=static=lua51");
} else {
let lib_path = format!("{}\\luajit.a", &src_dir);
if !std::fs::metadata(&lib_path).is_ok() {
let mut copy_options = CopyOptions::new();
copy_options.overwrite = true;
dir::copy(&luajit_dir, &out_dir, &copy_options).unwrap();
let mut buildcmd = Command::new("make");
buildcmd.current_dir(&src_dir);
buildcmd.stderr(Stdio::inherit());
let mut child = buildcmd.spawn().expect("failed to run make");
if !child
.wait()
.map(|status| status.success())
.map_err(|_| false)
.unwrap_or(false)
{
panic!("Failed to build luajit");
}
}
println!("cargo:rustc-link-search=native={}", src_dir);
println!("cargo:rustc-link-lib=static=luajit");
}
}

3
examples/hello.lua Normal file
View file

@ -0,0 +1,3 @@
print("Hello from lua")
return 1 + 2

54
examples/lua.rs Normal file
View file

@ -0,0 +1,54 @@
use std::env;
use std::ffi::{CStr, CString};
use std::ptr;
use luajit_sys as sys;
unsafe fn run_script(script_name: String, script_src: String) {
let lua = sys::luaL_newstate();
assert_ne!(lua, ptr::null_mut());
sys::luaL_openlibs(lua);
let script_data = script_src.as_bytes();
let script_name = CString::new(script_name).unwrap();
let mut error = sys::luaL_loadbuffer(
lua,
script_data.as_ptr() as _,
script_data.len() as _,
script_name.as_ptr() as _,
);
if error != 0 {
eprintln!("luaL_loadbuffer failed");
} else {
error = sys::lua_pcall(lua, 0, 1, 0);
if error != 0 {
eprintln!("lua_pcall failed");
}
}
let idx = sys::lua_gettop(lua);
if sys::lua_isnoneornil(lua, idx) != 1 {
let s = sys::lua_tostring(lua, idx);
assert_ne!(s, ptr::null(), "lua_tostring returned null");
let result = CStr::from_ptr(s).to_string_lossy().to_string();
println!("script result: {}", result);
}
sys::lua_close(lua);
}
fn main() {
if let Some(script_name) = env::args().skip(1).next() {
let script_src = std::fs::read_to_string(&script_name)
.unwrap_or_else(|e| panic!("failed to read file: '{}' {:?}", &script_name, e));
unsafe {
run_script(script_name, script_src);
}
} else {
println!(
"{} FILE",
env::current_exe()
.unwrap()
.file_name()
.unwrap()
.to_string_lossy()
);
}
}

4
ffi.h Normal file
View file

@ -0,0 +1,4 @@
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include "luajit.h"

1113
src/ffi.rs Normal file

File diff suppressed because it is too large Load diff

163
src/lib.rs Normal file
View file

@ -0,0 +1,163 @@
#![no_std]
#![allow(non_snake_case)]
#![allow(non_camel_case_types)]
//! # LuaJIT 2.1
//!
//! <http://luajit.org>
//!
//! <http://www.lua.org/manual/5.1/manual.html>
//!
//! ## Performance considerations
//!
//! The _Not Yet Implemented_ guide documents which language features will be JIT compiled
//! into native machine code.
//!
//! <http://wiki.luajit.org/NYI>
mod ffi;
pub use ffi::*;
use core::ptr;
// These are defined as macros
/// <https://www.lua.org/manual/5.1/manual.html#lua_pop>
#[inline]
pub unsafe fn lua_pop(L: *mut lua_State, idx: libc::c_int) {
lua_settop(L, -(idx) - 1)
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_newtable>
#[inline]
pub unsafe fn lua_newtable(L: *mut lua_State) {
lua_createtable(L, 0, 0)
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_register>
#[inline]
pub unsafe fn lua_register(L: *mut lua_State, name: *const libc::c_char, f: lua_CFunction) {
lua_pushcfunction(L, f);
lua_setglobal(L, name);
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_pushcfunction>
#[inline]
pub unsafe fn lua_pushcfunction(L: *mut lua_State, f: lua_CFunction) {
lua_pushcclosure(L, f, 0);
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_strlen>
#[inline]
pub unsafe fn lua_strlen(L: *mut lua_State, idx: libc::c_int) -> usize {
lua_objlen(L, idx)
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_isfunction>
#[inline]
pub unsafe fn lua_isfunction(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) == LUA_TFUNCTION as i32) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_istable>
#[inline]
pub unsafe fn lua_istable(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) == LUA_TTABLE as i32) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_islightuserdata>
#[inline]
pub unsafe fn lua_islightuserdata(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) == LUA_TLIGHTUSERDATA as i32) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_isnil>
#[inline]
pub unsafe fn lua_isnil(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) == LUA_TNIL as i32) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_isboolean>
#[inline]
pub unsafe fn lua_isboolean(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) == LUA_TBOOLEAN as i32) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_isthread>
#[inline]
pub unsafe fn lua_isthread(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) == LUA_TTHREAD as i32) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_isnone>
#[inline]
pub unsafe fn lua_isnone(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) == LUA_TNONE as i32) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_isnoneornil>
#[inline]
pub unsafe fn lua_isnoneornil(L: *mut lua_State, idx: libc::c_int) -> libc::c_int {
(lua_type(L, idx) <= 0) as i32
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_pushliteral>
#[inline]
pub unsafe fn lua_pushliteral(L: *mut lua_State, s: &str) {
lua_pushlstring(L, s.as_ptr() as _, s.len() as _);
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_setglobal>
#[inline]
pub unsafe fn lua_setglobal(L: *mut lua_State, k: *const libc::c_char) {
lua_setfield(L, LUA_GLOBALSINDEX, k);
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_getglobal>
#[inline]
pub unsafe fn lua_getglobal(L: *mut lua_State, k: *const libc::c_char) {
lua_getfield(L, LUA_GLOBALSINDEX, k)
}
/// <https://www.lua.org/manual/5.1/manual.html#lua_tostring>
#[inline]
pub unsafe fn lua_tostring(L: *mut lua_State, idx: libc::c_int) -> *const libc::c_char {
lua_tolstring(L, idx, ptr::null_mut())
}
// Additional compatibility items that are defined as macros
/// `luaL_newstate()`
#[inline]
#[deprecated(since = "Lua 5.1", note = "replace with `luaL_newstate()`")]
pub unsafe fn lua_open() -> *mut lua_State {
luaL_newstate()
}
/// `lua_pushvalue(L, LUA_REGISTRYINDEX)`
#[inline]
#[deprecated(
since = "Lua 5.1",
note = "replace with `lua_pushvalue(L, LUA_REGISTRYINDEX)`"
)]
pub unsafe fn lua_getregistry(L: *mut lua_State) {
lua_pushvalue(L, LUA_REGISTRYINDEX)
}
/// `lua_gc(L, LUA_GCCOUNT as _, 0)`
#[inline]
#[deprecated(
since = "Lua 5.1",
note = "replace with `lua_gc(L, LUA_GCCOUNT as _, 0)`"
)]
pub unsafe fn lua_getgccount(L: *mut lua_State) -> libc::c_int {
lua_gc(L, LUA_GCCOUNT as _, 0)
}
/// `lua_Reader`
#[deprecated(since = "Lua 5.1", note = "replace with `lua_Reader`")]
pub type lua_Chunkreader = lua_Reader;
/// `lua_Writer`
#[deprecated(since = "Lua 5.1", note = "replace with `lua_Writer`")]
pub type lua_Chunkwriter = lua_Writer;

40
tests/test.rs Normal file
View file

@ -0,0 +1,40 @@
use luajit_sys as sys;
#[test]
fn run_script() {
use std::ffi::CStr;
use std::ptr;
unsafe {
let lua = sys::luaL_newstate();
assert_ne!(lua, ptr::null_mut());
sys::luaL_openlibs(lua);
let script_data = b"return 1 + 2";
let script_name = b"run_script\0";
let mut error = sys::luaL_loadbuffer(
lua,
script_data.as_ptr() as _,
script_data.len() as _,
script_name.as_ptr() as _,
);
if error != 0 {
eprintln!("luaL_loadbuffer failed");
} else {
error = sys::lua_pcall(lua, 0, 1, 0);
if error != 0 {
eprintln!("lua_pcall failed");
}
}
let idx = sys::lua_gettop(lua);
println!("lua_gettop = {}", idx);
let s = sys::lua_tostring(lua, idx);
assert_ne!(s, ptr::null(), "lua_tostring returned null");
let result = CStr::from_ptr(s).to_string_lossy().to_string();
sys::lua_close(lua);
assert_eq!("3", result);
}
}