Skip to content

Commit e0d9ec4

Browse files
committed
Support cross compilation
This commit teaches the build script to recognize when it is cross-compiling and switch to an alternative approach for generating the `glue.rs` module. It defaults to the equivalent logic found in the lua headers to set the default types and parameters. Notably: it doesn't statically produce the default lua paths as we cannot know these without either executing the code (not guaranteed possible when cross compiling) or regexing out the paths from the headers (a bit brittle). An alternative approach might be to use something like `lazy_static` to ask the library for its compiled in values once at runtime. I've tested this with: ``` cargo build --target armv7-unknown-linux-gnueabihf --features lua51,vendored cargo build --target armv7-unknown-linux-gnueabihf --features lua52,vendored cargo build --target armv7-unknown-linux-gnueabihf --features lua53,vendored cargo build --target armv7-unknown-linux-gnueabihf --features lua54,vendored cargo build --target armv7-unknown-linux-gnueabihf --features luajit,vendored ``` All except luajit compile. Luajit itself doesn't cross compile, so I don't think we can ever reasonably get that to work. I haven't tried to run any of this yet; my use case is actually for mac (wezterm/wezterm#426) so I need to commit this and try patching it in over there before I can see if that truly worked end-to-end. refs: #14
1 parent 618874e commit e0d9ec4

File tree

1 file changed

+123
-1
lines changed

1 file changed

+123
-1
lines changed

build/main.rs

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,124 @@ fn build_glue<P: AsRef<Path> + std::fmt::Debug>(include_path: &P) {
9191
.unwrap();
9292
}
9393

94+
// When cross-compiling, we cannot use `build_glue` as we cannot run the generated
95+
// executable. Instead, let's take a stab at synthesizing the likely values.
96+
// If you're cross-compiling and using a non-vendored library then there is a chance
97+
// that the values selected here may be incorrect, but we have no way to determine
98+
// that here.
99+
fn generate_glue() -> std::io::Result<()> {
100+
use std::io::Write;
101+
let build_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
102+
let mut glue = std::fs::File::create(build_dir.join("glue.rs"))?;
103+
write!(
104+
glue,
105+
"/* This file was generated by build/main.rs; do not modify by hand */\n"
106+
)?;
107+
write!(glue, "use std::os::raw::*;\n")?;
108+
109+
// We can't statically determine the default paths.
110+
// It is possible though to use something like lazy_static! to create a new
111+
// lua context and extract that information.
112+
// For my (@wez) purposes, I actually don't want there to be a default path,
113+
// so I'm just leaving this blank for the moment.
114+
write!(glue, "pub const LUA_PATH_DEFAULT: &str = \"\";\n")?;
115+
write!(glue, "pub const LUA_CPATH_DEFAULT: &str = \"\";\n")?;
116+
117+
write!(
118+
glue,
119+
"#[cfg(windows)] pub const LUA_DIRSEP: &str = \"\\\\\";\n"
120+
)?;
121+
write!(glue, "#[cfg(unix)] pub const LUA_DIRSEP: &str = \"/\";\n")?;
122+
123+
let pointer_bit_width: usize = env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
124+
.unwrap()
125+
.parse()
126+
.unwrap();
127+
write!(
128+
glue,
129+
"pub const LUA_EXTRASPACE: c_int = {} / 8;\n",
130+
pointer_bit_width
131+
)?;
132+
133+
// This is generally hardcoded to this size
134+
write!(glue, "pub const LUA_IDSIZE: c_int = 60;\n")?;
135+
136+
write!(glue, "pub const LUAL_BUFFERSIZE: c_int = 16 * ({} / 8) * std::mem::size_of::<LUA_NUMBER>() as c_int;\n", pointer_bit_width)?;
137+
138+
// Unless the target is restricted, the defaults are 64 bit
139+
write!(glue, "pub type LUA_NUMBER = c_double;\n")?;
140+
write!(glue, "pub type LUA_INTEGER = i64;\n")?;
141+
write!(glue, "pub type LUA_UNSIGNED = u64;\n")?;
142+
143+
let version = if cfg!(feature = "luajit") || cfg!(feature = "lua51") {
144+
// Note: luajit is ~lua 5.1, but it doesn't itself cross compile
145+
(5, 1, 0)
146+
} else if cfg!(feature = "lua52") {
147+
(5, 2, 0)
148+
} else if cfg!(feature = "lua53") {
149+
(5, 3, 0)
150+
} else if cfg!(feature = "lua54") {
151+
(5, 4, 0)
152+
} else {
153+
unreachable!();
154+
};
155+
156+
write!(
157+
glue,
158+
"pub const LUA_VERSION_NUM: c_int = {};\n",
159+
(version.0 * 100) + version.1
160+
)?;
161+
write!(
162+
glue,
163+
"pub const LUA_VERSION: &str = \"Lua {}.{}\";\n",
164+
version.0, version.1
165+
)?;
166+
write!(
167+
glue,
168+
"pub const LUA_RELEASE: &str = \"Lua {}.{}.{}\";\n",
169+
version.0, version.1, version.2
170+
)?;
171+
172+
let max_stack = if pointer_bit_width >= 32 {
173+
1_000_000
174+
} else {
175+
15_000
176+
};
177+
write!(
178+
glue,
179+
"pub const LUA_REGISTRYINDEX: c_int = -{} - 1000;\n",
180+
max_stack
181+
)?;
182+
183+
// These two are only defined in lua 5.1
184+
write!(glue, "pub const LUA_ENVIRONINDEX: c_int = -10001;\n")?;
185+
write!(glue, "pub const LUA_GLOBALSINDEX: c_int = -10002;\n")?;
186+
187+
// This is only defined in lua 5.3 and up, but we can always generate its value here,
188+
// even if we don't use it.
189+
// This matches the default definition in lauxlib.h
190+
write!(glue, "pub const LUAL_NUMSIZES: c_int = std::mem::size_of::<LUA_INTEGER>() as c_int * 16 + std::mem::size_of::<LUA_NUMBER>() as c_int;\n")?;
191+
192+
write!(
193+
glue,
194+
r#"
195+
pub const LUA_BITLIBNAME: &str = "bit32";
196+
pub const LUA_COLIBNAME: &str = "coroutine";
197+
pub const LUA_DBLIBNAME: &str = "debug";
198+
pub const LUA_IOLIBNAME: &str = "io";
199+
pub const LUA_LOADLIBNAME: &str = "package";
200+
pub const LUA_MATHLIBNAME: &str = "math";
201+
pub const LUA_OSLIBNAME: &str = "os";
202+
pub const LUA_STRLIBNAME: &str = "string";
203+
pub const LUA_TABLIBNAME: &str = "table";
204+
pub const LUA_UTF8LIBNAME: &str = "utf8";
205+
206+
"#
207+
)?;
208+
209+
Ok(())
210+
}
211+
94212
fn main() {
95213
#[cfg(not(any(
96214
feature = "lua54",
@@ -132,5 +250,9 @@ fn main() {
132250
);
133251

134252
let include_dir = find::probe_lua();
135-
build_glue(&include_dir);
253+
if env::var("TARGET").unwrap() != env::var("HOST").unwrap() {
254+
generate_glue().unwrap();
255+
} else {
256+
build_glue(&include_dir);
257+
}
136258
}

0 commit comments

Comments
 (0)