1use std::env;
2use std::fs;
3use std::path::{Path, PathBuf};
4
5pub enum Version {
6 Lua51,
7 Lua52,
8 Lua53,
9 Lua54,
10 LuaFactorio52,
11}
12pub use self::Version::*;
13
14pub struct Build {
15 out_dir: Option<PathBuf>,
16 target: Option<String>,
17 host: Option<String>,
18}
19
20pub struct Artifacts {
21 include_dir: PathBuf,
22 lib_dir: PathBuf,
23 libs: Vec<String>,
24}
25
26impl Build {
27 #[allow(clippy::new_without_default)]
28 pub fn new() -> Build {
29 Build {
30 out_dir: env::var_os("OUT_DIR").map(|s| PathBuf::from(s).join("lua-build")),
31 target: env::var("TARGET").ok(),
32 host: env::var("HOST").ok(),
33 }
34 }
35
36 pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Build {
37 self.out_dir = Some(path.as_ref().to_path_buf());
38 self
39 }
40
41 pub fn target(&mut self, target: &str) -> &mut Build {
42 self.target = Some(target.to_string());
43 self
44 }
45
46 pub fn host(&mut self, host: &str) -> &mut Build {
47 self.host = Some(host.to_string());
48 self
49 }
50
51 pub fn build(&mut self, version: Version) -> Artifacts {
52 let target = &self.target.as_ref().expect("TARGET not set")[..];
53 let host = &self.host.as_ref().expect("HOST not set")[..];
54 let out_dir = self.out_dir.as_ref().expect("OUT_DIR not set");
55 let lib_dir = out_dir.join("lib");
56 let include_dir = out_dir.join("include");
57
58 let source_dir_base = Path::new(env!("CARGO_MANIFEST_DIR"));
59 let source_dir = match version {
60 Lua51 => source_dir_base.join("lua-5.1.5"),
61 Lua52 => source_dir_base.join("lua-5.2.4"),
62 Lua53 => source_dir_base.join("lua-5.3.6"),
63 Lua54 => source_dir_base.join("lua-5.4.6"),
64 LuaFactorio52 => source_dir_base.join("lua-factorio-5.2.1/src"),
65 };
66
67 if lib_dir.exists() {
68 fs::remove_dir_all(&lib_dir).unwrap();
69 }
70 fs::create_dir_all(&lib_dir).unwrap();
71
72 if include_dir.exists() {
73 fs::remove_dir_all(&include_dir).unwrap();
74 }
75 fs::create_dir_all(&include_dir).unwrap();
76
77 let mut config = cc::Build::new();
78 config
79 .target(target)
80 .host(host)
81 .warnings(false)
82 .opt_level(2)
83 .cargo_metadata(false);
84
85 match target {
86 _ if target.contains("linux") => {
87 config.define("LUA_USE_LINUX", None);
88 }
89 _ if target.contains("freebsd") => {
90 config.define("LUA_USE_LINUX", None);
91 }
92 _ if target.contains("netbsd") => {
93 config.define("LUA_USE_LINUX", None);
94 }
95 _ if target.contains("openbsd") => {
96 config.define("LUA_USE_LINUX", None);
97 }
98 _ if target.contains("apple-darwin") => {
99 match version {
100 Lua51 => config.define("LUA_USE_LINUX", None),
101 _ => config.define("LUA_USE_MACOSX", None),
102 };
103 }
104 _ if target.contains("windows") => {
105 config.define("LUA_USE_WINDOWS", None);
107 }
108 _ => panic!("don't know how to build Lua for {}", target),
109 };
110
111 if let Lua54 = version {
112 config.define("LUA_COMPAT_5_3", None);
113 #[cfg(feature = "ucid")]
114 config.define("LUA_UCID", None);
115 }
116
117 if cfg!(debug_assertions) {
118 config.define("LUA_USE_APICHECK", None);
119 }
120
121 let lib_name = match version {
122 Lua51 => "lua5.1",
123 Lua52 | LuaFactorio52 => "lua5.2",
124 Lua53 => "lua5.3",
125 Lua54 => "lua5.4",
126 };
127
128 if let LuaFactorio52 = version {
129 config
130 .cpp(true)
131 .flag_if_supported("-TP")
132 .define("USE_LUA_PACKAGE", None);
133 }
134
135 config
136 .include(&source_dir)
137 .flag("-w") .flag_if_supported("-fno-common") .file(source_dir.join("lapi.c"))
140 .file(source_dir.join("lauxlib.c"))
141 .file(source_dir.join("lbaselib.c"))
142 .file(source_dir.join("lcode.c"))
144 .file(source_dir.join("ldblib.c"))
147 .file(source_dir.join("ldebug.c"))
148 .file(source_dir.join("ldo.c"))
149 .file(source_dir.join("ldump.c"))
150 .file(source_dir.join("lfunc.c"))
151 .file(source_dir.join("lgc.c"))
152 .file(source_dir.join("linit.c"))
153 .file(source_dir.join("liolib.c"))
154 .file(source_dir.join("llex.c"))
155 .file(source_dir.join("lmathlib.c"))
156 .file(source_dir.join("lmem.c"))
157 .file(source_dir.join("loadlib.c"))
158 .file(source_dir.join("lobject.c"))
159 .file(source_dir.join("lopcodes.c"))
160 .file(source_dir.join("loslib.c"))
161 .file(source_dir.join("lparser.c"))
162 .file(source_dir.join("lstate.c"))
163 .file(source_dir.join("lstring.c"))
164 .file(source_dir.join("lstrlib.c"))
165 .file(source_dir.join("ltable.c"))
166 .file(source_dir.join("ltablib.c"))
167 .file(source_dir.join("ltm.c"))
168 .file(source_dir.join("lundump.c"))
169 .file(source_dir.join("lvm.c"))
171 .file(source_dir.join("lzio.c"));
172
173 match version {
174 Lua51 => {}
175 Lua52 => {
176 config
177 .file(source_dir.join("lbitlib.c"))
178 .file(source_dir.join("lcorolib.c"))
179 .file(source_dir.join("lctype.c"));
180 }
181 LuaFactorio52 => {
182 config
183 .file(source_dir.join("lbitlib.c"))
184 .file(source_dir.join("lcorolib.c"))
185 .file(source_dir.join("lctype.c"));
186 }
187 Lua53 => {
188 config
189 .file(source_dir.join("lbitlib.c"))
190 .file(source_dir.join("lcorolib.c"))
191 .file(source_dir.join("lctype.c"))
192 .file(source_dir.join("lutf8lib.c"));
193 }
194 Lua54 => {
195 config
196 .file(source_dir.join("lcorolib.c"))
197 .file(source_dir.join("lctype.c"))
198 .file(source_dir.join("lutf8lib.c"));
199 }
200 }
201
202 config.out_dir(&lib_dir).compile(lib_name);
203
204 for f in &["lauxlib.h", "lua.h", "luaconf.h", "lualib.h"] {
205 fs::copy(source_dir.join(f), include_dir.join(f)).unwrap();
206 }
207
208 if let LuaFactorio52 = version {
209 fs::copy(source_dir.join("lua.hpp"), include_dir.join("lua.hpp")).unwrap();
210 }
211
212 Artifacts {
213 lib_dir,
214 include_dir,
215 libs: vec![lib_name.to_string()],
216 }
217 }
218}
219
220impl Artifacts {
221 pub fn include_dir(&self) -> &Path {
222 &self.include_dir
223 }
224
225 pub fn lib_dir(&self) -> &Path {
226 &self.lib_dir
227 }
228
229 pub fn libs(&self) -> &[String] {
230 &self.libs
231 }
232
233 pub fn print_cargo_metadata(&self) {
234 println!("cargo:rustc-link-search=native={}", self.lib_dir.display());
235 for lib in self.libs.iter() {
236 println!("cargo:rustc-link-lib=static={}", lib);
237 }
238 println!("cargo:include={}", self.include_dir.display());
239 println!("cargo:lib={}", self.lib_dir.display());
240 }
241}