lux_lib/build/
rust_mlua.rs1use super::external_dependency::ExternalDependencyInfo;
2use super::utils::c_dylib_extension;
3use crate::config::LuaVersionUnset;
4use crate::lua_rockspec::BuildInfo;
5use crate::progress::{Progress, ProgressBar};
6use crate::tree::Tree;
7use crate::{
8 config::{Config, LuaVersion},
9 lua_installation::LuaInstallation,
10 lua_rockspec::{Build, RustMluaBuildSpec},
11 tree::RockLayout,
12};
13use itertools::Itertools;
14use std::collections::HashMap;
15use std::path::{Path, PathBuf};
16use std::process::ExitStatus;
17use std::{fs, io};
18use thiserror::Error;
19use tokio::process::Command;
20
21#[derive(Error, Debug)]
22pub enum RustError {
23 #[error("`cargo build` failed.\nstatus: {status}\nstdout: {stdout}\nstderr: {stderr}")]
24 CargoBuild {
25 status: ExitStatus,
26 stdout: String,
27 stderr: String,
28 },
29 #[error("failed to run `cargo build`: {0}")]
30 RustBuild(#[from] io::Error),
31 #[error(transparent)]
32 LuaVersionUnset(#[from] LuaVersionUnset),
33}
34
35impl Build for RustMluaBuildSpec {
36 type Err = RustError;
37
38 async fn run(
39 self,
40 output_paths: &RockLayout,
41 _no_install: bool,
42 _lua: &LuaInstallation,
43 _external_dependencies: &HashMap<String, ExternalDependencyInfo>,
44 config: &Config,
45 _tree: &Tree,
46 build_dir: &Path,
47 progress: &Progress<ProgressBar>,
48 ) -> Result<BuildInfo, Self::Err> {
49 let lua_version = LuaVersion::from(config)?;
50 let lua_feature = match lua_version {
51 LuaVersion::Lua51 => "lua51",
52 LuaVersion::Lua52 => "lua52",
53 LuaVersion::Lua53 => "lua53",
54 LuaVersion::Lua54 => "lua54",
55 LuaVersion::LuaJIT => "luajit",
56 LuaVersion::LuaJIT52 => "luajit",
57 };
58 let features = self
59 .features
60 .into_iter()
61 .chain(std::iter::once(lua_feature.into()))
62 .join(",");
63 let target_dir_arg = format!("--target-dir={}", self.target_path.display());
64 let mut build_args = vec!["build", "--release", &target_dir_arg];
65 if !self.default_features {
66 build_args.push("--no-default-features");
67 }
68 build_args.push("--features");
69 build_args.push(&features);
70 match Command::new("cargo")
71 .current_dir(build_dir)
72 .args(build_args)
73 .output()
74 .await
75 {
76 Ok(output) if output.status.success() => {}
77 Ok(output) => {
78 return Err(RustError::CargoBuild {
79 status: output.status,
80 stdout: String::from_utf8_lossy(&output.stdout).into(),
81 stderr: String::from_utf8_lossy(&output.stderr).into(),
82 });
83 }
84 Err(err) => return Err(RustError::RustBuild(err)),
85 }
86 fs::create_dir_all(&output_paths.lib)?;
87 if let Err(err) =
88 install_rust_libs(self.modules, &self.target_path, build_dir, output_paths)
89 {
90 cleanup(output_paths, progress).await?;
91 return Err(err.into());
92 }
93 fs::create_dir_all(&output_paths.src)?;
94 if let Err(err) = install_lua_libs(self.include, build_dir, output_paths) {
95 cleanup(output_paths, progress).await?;
96 return Err(err.into());
97 }
98 Ok(BuildInfo::default())
99 }
100}
101
102fn install_rust_libs(
103 modules: HashMap<String, PathBuf>,
104 target_path: &Path,
105 build_dir: &Path,
106 output_paths: &RockLayout,
107) -> io::Result<()> {
108 for (module, rust_lib) in modules {
109 let src = build_dir.join(target_path).join("release").join(rust_lib);
110 let mut dst: PathBuf = output_paths.lib.join(module);
111 dst.set_extension(c_dylib_extension());
112 fs::copy(src, dst)?;
113 }
114 Ok(())
115}
116
117fn install_lua_libs(
118 include: HashMap<PathBuf, PathBuf>,
119 build_dir: &Path,
120 output_paths: &RockLayout,
121) -> io::Result<()> {
122 for (from, to) in include {
123 let src = build_dir.join(from);
124 let dst = output_paths.src.join(to);
125 fs::copy(src, dst)?;
126 }
127 Ok(())
128}
129
130async fn cleanup(output_paths: &RockLayout, progress: &Progress<ProgressBar>) -> io::Result<()> {
131 let root_dir = &output_paths.rock_path;
132
133 progress.map(|p| p.set_message(format!("🗑️ Cleaning up {}", root_dir.display())));
134
135 match std::fs::remove_dir_all(root_dir) {
136 Ok(_) => (),
137 Err(err) => {
138 progress
139 .map(|p| p.println(format!("Error cleaning up {}: {}", root_dir.display(), err)));
140 }
141 };
142
143 Ok(())
144}