#![allow(unreachable_code)] use std::env; use std::fs::File; use std::io::{Error, ErrorKind, Result, Write}; use std::path::{Path, PathBuf}; use std::process::Command; #[cfg_attr( all( feature = "vendored", any( feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit" ) ), path = "find_vendored.rs" )] #[cfg_attr( all( not(feature = "vendored"), any( feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit" ) ), path = "find_normal.rs" )] #[cfg_attr( not(any( feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit" )), path = "find_dummy.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 + 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(); } // When cross-compiling, we cannot use `build_glue` as we cannot run the generated // executable. Instead, let's take a stab at synthesizing the likely values. // If you're cross-compiling and using a non-vendored library then there is a chance // that the values selected here may be incorrect, but we have no way to determine // that here. fn generate_glue() -> Result<()> { let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); let mut glue = File::create(build_dir.join("glue.rs"))?; writeln!( glue, "/* This file was generated by build/main.rs; do not modify by hand */" )?; writeln!(glue, "use std::os::raw::*;")?; writeln!(glue, "/* luaconf.h */")?; let pointer_bit_width: usize = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") .unwrap() .parse() .unwrap(); writeln!( glue, "pub const LUA_EXTRASPACE: c_int = {} / 8;", pointer_bit_width )?; // This is generally hardcoded to this size writeln!(glue, "pub const LUA_IDSIZE: c_int = 60;")?; // Unless the target is restricted, the defaults are 64 bit writeln!(glue, "pub type LUA_NUMBER = c_double;")?; writeln!(glue, "pub type LUA_INTEGER = i64;")?; writeln!(glue, "pub type LUA_UNSIGNED = u64;")?; writeln!(glue, "/* lua.h */")?; let version = if cfg!(any(feature = "luajit", feature = "lua51")) { (5, 1, 0) } else if cfg!(feature = "lua52") { (5, 2, 0) } else if cfg!(feature = "lua53") { (5, 3, 0) } else if cfg!(feature = "lua54") { (5, 4, 0) } else { unreachable!(); }; writeln!( glue, "pub const LUA_VERSION_NUM: c_int = {};", (version.0 * 100) + version.1 )?; let max_stack = if pointer_bit_width >= 32 { 1_000_000 } else { 15_000 }; writeln!( glue, "pub const LUA_REGISTRYINDEX: c_int = -{} - 1000;", max_stack )?; // These two are only defined in lua 5.1 writeln!(glue, "pub const LUA_ENVIRONINDEX: c_int = -10001;")?; writeln!(glue, "pub const LUA_GLOBALSINDEX: c_int = -10002;")?; writeln!(glue, "/* lauxlib.h */")?; // This is only defined in lua 5.3 and up, but we can always generate its value here, // even if we don't use it. // This matches the default definition in lauxlib.h writeln!(glue, "pub const LUAL_NUMSIZES: c_int = std::mem::size_of::() as c_int * 16 + std::mem::size_of::() as c_int;")?; writeln!(glue, "/* lualib.h */")?; write!( glue, r#" #[cfg(feature = "luajit")] pub const LUA_BITLIBNAME: &str = "bit"; #[cfg(not(feature = "luajit"))] pub const LUA_BITLIBNAME: &str = "bit32"; pub const LUA_COLIBNAME: &str = "coroutine"; pub const LUA_DBLIBNAME: &str = "debug"; pub const LUA_IOLIBNAME: &str = "io"; pub const LUA_LOADLIBNAME: &str = "package"; pub const LUA_MATHLIBNAME: &str = "math"; pub const LUA_OSLIBNAME: &str = "os"; pub const LUA_STRLIBNAME: &str = "string"; pub const LUA_TABLIBNAME: &str = "table"; pub const LUA_UTF8LIBNAME: &str = "utf8"; pub const LUA_JITLIBNAME: &str = "jit"; pub const LUA_FFILIBNAME: &str = "ffi"; "# )?; Ok(()) } fn main() { #[cfg(not(any( feature = "lua54", feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit" )))] compile_error!("You must enable one of the features: lua54, lua53, lua52, lua51, luajit"); #[cfg(all( feature = "lua54", any( feature = "lua53", feature = "lua52", feature = "lua51", feature = "luajit" ) ))] compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit"); #[cfg(all( feature = "lua53", any(feature = "lua52", feature = "lua51", feature = "luajit") ))] compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit"); #[cfg(all(feature = "lua52", any(feature = "lua51", feature = "luajit")))] compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit"); #[cfg(all(feature = "lua51", feature = "luajit"))] compile_error!("You can enable only one of the features: lua54, lua53, lua52, lua51, luajit"); // We don't support "vendored module" mode on windows #[cfg(all(feature = "vendored", feature = "module", target_os = "windows"))] compile_error!( "Vendored (static) builds are not supported for modules on Windows.\n" + "Please, use `pkg-config` or custom mode to link to a Lua dll." ); let include_dir = find::probe_lua(); if env::var("TARGET").unwrap() != env::var("HOST").unwrap() { generate_glue().unwrap(); } else { build_glue(&include_dir); } }