diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d62d342..4d92f78 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -72,6 +72,47 @@ jobs: TRYBUILD=overwrite cargo test --release --features "${{ matrix.lua }} vendored async send serialize" -- --ignored shell: bash + test_arm_cross_macos: + name: Test Cross compilation for ARM from Intel on macOS + runs-on: macos-11.0 + strategy: + matrix: + lua: [lua54, lua53, lua52, lua51] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + target: x86_64-apple-darwin + override: true + - name: Add ARM target + run: rustup target add aarch64-apple-darwin + - name: Cross compile + run: cargo build --target aarch64-apple-darwin --features "${{ matrix.lua }} async send serialize vendored" + + test_arm_cross_ubuntu: + name: Test cross compilation for ARM from Intel on Linux + runs-on: ubuntu-18.04 + strategy: + matrix: + lua: [lua54, lua53, lua52, lua51] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + target: x86_64-unknown-linux-gnu + override: true + - name: Add ARM target + run: rustup target add armv7-unknown-linux-gnueabihf + - name: Install ARM compiler toolchain + run: | + sudo apt-get update -y + sudo apt-get install -y --no-install-recommends gcc-arm-linux-gnueabihf libc-dev-armhf-cross + - name: Cross compile + run: cargo build --target armv7-unknown-linux-gnueabihf --features "${{ matrix.lua }} async send serialize vendored" + shell: bash + test_luajit_macos: name: Test LuaJIT on macOS runs-on: macos-latest diff --git a/build/main.rs b/build/main.rs index a0f4469..0aa1e78 100644 --- a/build/main.rs +++ b/build/main.rs @@ -91,6 +91,129 @@ fn build_glue + std::fmt::Debug>(include_path: &P) { .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() -> std::io::Result<()> { + use std::io::Write; + let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); + let mut glue = std::fs::File::create(build_dir.join("glue.rs"))?; + write!( + glue, + "/* This file was generated by build/main.rs; do not modify by hand */\n" + )?; + write!(glue, "use std::os::raw::*;\n")?; + + // We can't statically determine the default paths. + // It is possible though to use something like lazy_static! to create a new + // lua context and extract that information. + // For my (@wez) purposes, I actually don't want there to be a default path, + // so I'm just leaving this blank for the moment. + write!(glue, "pub const LUA_PATH_DEFAULT: &str = \"\";\n")?; + write!(glue, "pub const LUA_CPATH_DEFAULT: &str = \"\";\n")?; + + write!( + glue, + "#[cfg(windows)] pub const LUA_DIRSEP: &str = \"\\\\\";\n" + )?; + write!(glue, "#[cfg(unix)] pub const LUA_DIRSEP: &str = \"/\";\n")?; + + let pointer_bit_width: usize = env::var("CARGO_CFG_TARGET_POINTER_WIDTH") + .unwrap() + .parse() + .unwrap(); + write!( + glue, + "pub const LUA_EXTRASPACE: c_int = {} / 8;\n", + pointer_bit_width + )?; + + // This is generally hardcoded to this size + write!(glue, "pub const LUA_IDSIZE: c_int = 60;\n")?; + + write!(glue, "pub const LUAL_BUFFERSIZE: c_int = 16 * ({} / 8) * std::mem::size_of::() as c_int;\n", pointer_bit_width)?; + + // Unless the target is restricted, the defaults are 64 bit + write!(glue, "pub type LUA_NUMBER = c_double;\n")?; + write!(glue, "pub type LUA_INTEGER = i64;\n")?; + write!(glue, "pub type LUA_UNSIGNED = u64;\n")?; + + let version = if cfg!(feature = "luajit") || cfg!(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!(); + }; + + write!( + glue, + "pub const LUA_VERSION_NUM: c_int = {};\n", + (version.0 * 100) + version.1 + )?; + write!( + glue, + "pub const LUA_VERSION: &str = \"Lua {}.{}\";\n", + version.0, version.1 + )?; + write!( + glue, + "pub const LUA_RELEASE: &str = \"Lua {}.{}.{}\";\n", + version.0, version.1, version.2 + )?; + + let max_stack = if pointer_bit_width >= 32 { + 1_000_000 + } else { + 15_000 + }; + write!( + glue, + "pub const LUA_REGISTRYINDEX: c_int = -{} - 1000;\n", + max_stack + )?; + + // These two are only defined in lua 5.1 + write!(glue, "pub const LUA_ENVIRONINDEX: c_int = -10001;\n")?; + write!(glue, "pub const LUA_GLOBALSINDEX: c_int = -10002;\n")?; + + // 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 + write!(glue, "pub const LUAL_NUMSIZES: c_int = std::mem::size_of::() as c_int * 16 + std::mem::size_of::() as c_int;\n")?; + + 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", @@ -132,5 +255,9 @@ fn main() { ); let include_dir = find::probe_lua(); - build_glue(&include_dir); + if env::var("TARGET").unwrap() != env::var("HOST").unwrap() { + generate_glue().unwrap(); + } else { + build_glue(&include_dir); + } }