mirror of
https://github.com/lune-org/lune.git
synced 2025-04-19 19:34:02 +01:00
feat: cross compilation target system
This commit is contained in:
parent
baa03424d4
commit
119eecad0d
2 changed files with 117 additions and 10 deletions
123
src/cli/build.rs
123
src/cli/build.rs
|
@ -7,11 +7,23 @@ use std::{
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use console::style;
|
use console::style;
|
||||||
|
use directories::BaseDirs;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use tokio::{fs, io::AsyncWriteExt as _};
|
use tokio::{fs, io::AsyncWriteExt as _};
|
||||||
|
|
||||||
use crate::standalone::metadata::Metadata;
|
use crate::standalone::metadata::Metadata;
|
||||||
|
|
||||||
/// Build a standalone executable
|
const TARGET_BASE_DIR: Lazy<PathBuf> = Lazy::new(|| {
|
||||||
|
BaseDirs::new()
|
||||||
|
.unwrap()
|
||||||
|
.home_dir()
|
||||||
|
.to_path_buf()
|
||||||
|
.join(".lune")
|
||||||
|
.join("target")
|
||||||
|
.join(env!("CARGO_PKG_VERSION"))
|
||||||
|
});
|
||||||
|
|
||||||
|
// Build a standalone executable
|
||||||
#[derive(Debug, Clone, Parser)]
|
#[derive(Debug, Clone, Parser)]
|
||||||
pub struct BuildCommand {
|
pub struct BuildCommand {
|
||||||
/// The path to the input file
|
/// The path to the input file
|
||||||
|
@ -21,35 +33,123 @@ pub struct BuildCommand {
|
||||||
/// input file path with an executable extension
|
/// input file path with an executable extension
|
||||||
#[clap(short, long)]
|
#[clap(short, long)]
|
||||||
pub output: Option<PathBuf>,
|
pub output: Option<PathBuf>,
|
||||||
|
|
||||||
|
#[clap(short, long)]
|
||||||
|
pub target: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildCommand {
|
impl BuildCommand {
|
||||||
pub async fn run(self) -> Result<ExitCode> {
|
pub async fn run(self) -> Result<ExitCode> {
|
||||||
let output_path = self
|
let mut output_path = self
|
||||||
.output
|
.output
|
||||||
.unwrap_or_else(|| self.input.with_extension(EXE_EXTENSION));
|
.unwrap_or_else(|| self.input.with_extension(EXE_EXTENSION));
|
||||||
|
|
||||||
let input_path_displayed = self.input.display();
|
let input_path_displayed = self.input.display();
|
||||||
let output_path_displayed = output_path.display();
|
|
||||||
|
|
||||||
// Try to read the input file
|
// Try to read the input file
|
||||||
let source_code = fs::read(&self.input)
|
let source_code = fs::read(&self.input)
|
||||||
.await
|
.await
|
||||||
.context("failed to read input file")?;
|
.context("failed to read input file")?;
|
||||||
|
|
||||||
|
let base_exe_path = if let Some(target_inner) = self.target {
|
||||||
|
let target_exe_extension = get_target_exe_extension(target_inner.as_str());
|
||||||
|
|
||||||
|
let path =
|
||||||
|
TARGET_BASE_DIR.join(format!("lune-{}.{}", target_inner, target_exe_extension));
|
||||||
|
|
||||||
|
output_path = output_path.with_extension(target_exe_extension);
|
||||||
|
|
||||||
|
if !TARGET_BASE_DIR.exists() {
|
||||||
|
fs::create_dir_all(TARGET_BASE_DIR.to_path_buf()).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !path.exists() {
|
||||||
|
println!("Requested target hasn't been downloaded yet, attempting to download");
|
||||||
|
|
||||||
|
let release_url = format!(
|
||||||
|
"https://github.com/lune-org/lune/releases/download/v{ver}/lune-{ver}-{target}.zip",
|
||||||
|
ver = env!("CARGO_PKG_VERSION"),
|
||||||
|
target = target_inner
|
||||||
|
);
|
||||||
|
|
||||||
|
let target_full_display = release_url
|
||||||
|
.split("/")
|
||||||
|
.last()
|
||||||
|
.or(Some("lune-UNKNOWN-UNKNOWN"))
|
||||||
|
.unwrap()
|
||||||
|
.replace("zip", target_exe_extension);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"{} target {}",
|
||||||
|
style("Download").green().bold(),
|
||||||
|
target_full_display
|
||||||
|
);
|
||||||
|
|
||||||
|
// Maybe we should use the custom net client used in `@lune/net`
|
||||||
|
let dl_req = match reqwest::get(release_url).await {
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!(
|
||||||
|
" {} Unable to download base binary found for target `{}`",
|
||||||
|
style("Download").red().bold(),
|
||||||
|
target_inner,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(ExitCode::FAILURE);
|
||||||
|
}
|
||||||
|
Ok(resp) => {
|
||||||
|
let resp_status = resp.status();
|
||||||
|
|
||||||
|
if resp_status != 200 && !resp_status.is_redirection() {
|
||||||
|
eprintln!(
|
||||||
|
" {} No precompiled base binary found for target `{}`",
|
||||||
|
style("Download").red().bold(),
|
||||||
|
target_inner
|
||||||
|
);
|
||||||
|
|
||||||
|
println!("{}: {}", style("HINT").yellow(), style("Perhaps try providing a path to self-compiled target with the `--base` flag").italic());
|
||||||
|
|
||||||
|
return Ok(ExitCode::FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
resp
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.open(&path)
|
||||||
|
.await?
|
||||||
|
.write_all(&dl_req.bytes().await?)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
println!(
|
||||||
|
" {} {}",
|
||||||
|
style("Downloaded").blue(),
|
||||||
|
style(target_full_display).underlined()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(path)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
// Read the contents of the lune interpreter as our starting point
|
// Read the contents of the lune interpreter as our starting point
|
||||||
println!(
|
println!(
|
||||||
"Creating standalone binary using {}",
|
"{} standalone binary using {}",
|
||||||
style(input_path_displayed).green()
|
style("Compile").green().bold(),
|
||||||
|
style(input_path_displayed).underlined()
|
||||||
);
|
);
|
||||||
let patched_bin = Metadata::create_env_patched_bin(source_code.clone())
|
let patched_bin = Metadata::create_env_patched_bin(base_exe_path, source_code.clone())
|
||||||
.await
|
.await
|
||||||
.context("failed to create patched binary")?;
|
.context("failed to create patched binary")?;
|
||||||
|
|
||||||
// And finally write the patched binary to the output file
|
// And finally write the patched binary to the output file
|
||||||
println!(
|
println!(
|
||||||
"Writing standalone binary to {}",
|
" {} standalone binary to {}",
|
||||||
style(output_path_displayed).blue()
|
style("Write").blue().bold(),
|
||||||
|
style(output_path.display()).underlined()
|
||||||
);
|
);
|
||||||
write_executable_file_to(output_path, patched_bin).await?;
|
write_executable_file_to(output_path, patched_bin).await?;
|
||||||
|
|
||||||
|
@ -71,3 +171,10 @@ async fn write_executable_file_to(path: impl AsRef<Path>, bytes: impl AsRef<[u8]
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_target_exe_extension(target: &str) -> &str {
|
||||||
|
match target {
|
||||||
|
"windows-x86_64" => "exe",
|
||||||
|
_ => "bin",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -49,8 +49,8 @@ impl Metadata {
|
||||||
/**
|
/**
|
||||||
Creates a patched standalone binary from the given script contents.
|
Creates a patched standalone binary from the given script contents.
|
||||||
*/
|
*/
|
||||||
pub async fn create_env_patched_bin(script_contents: impl Into<Vec<u8>>) -> Result<Vec<u8>> {
|
pub async fn create_env_patched_bin(base_exe_path: Option<PathBuf>, script_contents: impl Into<Vec<u8>>) -> Result<Vec<u8>> {
|
||||||
let mut patched_bin = fs::read(CURRENT_EXE.to_path_buf()).await?;
|
let mut patched_bin = fs::read(base_exe_path.unwrap_or(CURRENT_EXE.to_path_buf())).await?;
|
||||||
|
|
||||||
// Compile luau input into bytecode
|
// Compile luau input into bytecode
|
||||||
let bytecode = LuaCompiler::new()
|
let bytecode = LuaCompiler::new()
|
||||||
|
|
Loading…
Add table
Reference in a new issue