mirror of
https://github.com/lune-org/lune.git
synced 2025-04-11 22:10:53 +01:00
84 lines
2.7 KiB
Rust
84 lines
2.7 KiB
Rust
use console::Style;
|
|
use std::{
|
|
env,
|
|
path::{Path, PathBuf},
|
|
process::ExitCode,
|
|
};
|
|
use tokio::{
|
|
fs::{self, OpenOptions},
|
|
io::AsyncWriteExt,
|
|
};
|
|
|
|
use anyhow::Result;
|
|
use mlua::Compiler as LuaCompiler;
|
|
|
|
/**
|
|
Compiles and embeds the bytecode of a requested lua file to form a standalone binary,
|
|
then writes it to an output file, with the required permissions.
|
|
*/
|
|
#[allow(clippy::similar_names)]
|
|
pub async fn build_standalone<T: AsRef<Path> + Into<PathBuf>>(
|
|
script_path: String,
|
|
output_path: T,
|
|
code: impl AsRef<[u8]>,
|
|
) -> Result<ExitCode> {
|
|
let log_output_path = output_path.as_ref().display();
|
|
|
|
let prefix_style = Style::new().green().bold();
|
|
let compile_prefix = prefix_style.apply_to("Compile");
|
|
let bytecode_prefix = prefix_style.apply_to("Bytecode");
|
|
let write_prefix = prefix_style.apply_to("Write");
|
|
let compiled_prefix = prefix_style.apply_to("Compiled");
|
|
|
|
println!("{compile_prefix} {script_path}");
|
|
|
|
// First, we read the contents of the lune interpreter as our starting point
|
|
let mut patched_bin = fs::read(env::current_exe()?).await?;
|
|
let base_bin_offset = u64::try_from(patched_bin.len())?;
|
|
|
|
// The signature which separates indicates the presence of bytecode to execute
|
|
// If a binary contains this signature, that must mean it is a standalone binary
|
|
let signature: Vec<u8> = vec![0x4f, 0x3e, 0xf8, 0x41, 0xc3, 0x3a, 0x52, 0x16];
|
|
|
|
// Compile luau input into bytecode
|
|
let bytecode = LuaCompiler::new()
|
|
.set_optimization_level(2)
|
|
.set_coverage_level(0)
|
|
.set_debug_level(0)
|
|
.compile(code);
|
|
|
|
println!(" {bytecode_prefix} {script_path}");
|
|
|
|
patched_bin.append(&mut bytecode.clone());
|
|
|
|
let mut meta = base_bin_offset.to_ne_bytes().to_vec();
|
|
|
|
// Include metadata in the META chunk, each field is 8 bytes
|
|
meta.append(&mut (bytecode.len() as u64).to_ne_bytes().to_vec()); // Size of bytecode, used to calculate end offset at runtime
|
|
meta.append(&mut 1_u64.to_ne_bytes().to_vec()); // Number of files, padded with null bytes - for future use
|
|
|
|
patched_bin.append(&mut meta);
|
|
|
|
// Append the signature to the base binary
|
|
patched_bin.append(&mut signature.clone());
|
|
|
|
// Write the compiled binary to file
|
|
#[cfg(target_family = "unix")]
|
|
OpenOptions::new()
|
|
.write(true)
|
|
.create(true)
|
|
.mode(0o770) // read, write and execute permissions for user and group
|
|
.open(&output_path)
|
|
.await?
|
|
.write_all(&patched_bin)
|
|
.await?;
|
|
|
|
#[cfg(target_family = "windows")]
|
|
fs::write(&output_path, &patched_bin).await?;
|
|
|
|
println!(" {write_prefix} {log_output_path}");
|
|
|
|
println!("{compiled_prefix} {log_output_path}");
|
|
|
|
Ok(ExitCode::SUCCESS)
|
|
}
|