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.cpp(true).define("USE_LUA_PACKAGE", None);
130 }
131
132 config
133 .include(&source_dir)
134 .flag("-w") .flag_if_supported("-fno-common") .file(source_dir.join("lapi.c"))
137 .file(source_dir.join("lauxlib.c"))
138 .file(source_dir.join("lbaselib.c"))
139 .file(source_dir.join("lcode.c"))
141 .file(source_dir.join("ldblib.c"))
144 .file(source_dir.join("ldebug.c"))
145 .file(source_dir.join("ldo.c"))
146 .file(source_dir.join("ldump.c"))
147 .file(source_dir.join("lfunc.c"))
148 .file(source_dir.join("lgc.c"))
149 .file(source_dir.join("linit.c"))
150 .file(source_dir.join("liolib.c"))
151 .file(source_dir.join("llex.c"))
152 .file(source_dir.join("lmathlib.c"))
153 .file(source_dir.join("lmem.c"))
154 .file(source_dir.join("loadlib.c"))
155 .file(source_dir.join("lobject.c"))
156 .file(source_dir.join("lopcodes.c"))
157 .file(source_dir.join("loslib.c"))
158 .file(source_dir.join("lparser.c"))
159 .file(source_dir.join("lstate.c"))
160 .file(source_dir.join("lstring.c"))
161 .file(source_dir.join("lstrlib.c"))
162 .file(source_dir.join("ltable.c"))
163 .file(source_dir.join("ltablib.c"))
164 .file(source_dir.join("ltm.c"))
165 .file(source_dir.join("lundump.c"))
166 .file(source_dir.join("lvm.c"))
168 .file(source_dir.join("lzio.c"));
169
170 match version {
171 Lua51 => {}
172 Lua52 => {
173 config
174 .file(source_dir.join("lbitlib.c"))
175 .file(source_dir.join("lcorolib.c"))
176 .file(source_dir.join("lctype.c"));
177 }
178 LuaFactorio52 => {
179 config
180 .file(source_dir.join("lbitlib.c"))
181 .file(source_dir.join("lcorolib.c"))
182 .file(source_dir.join("lctype.c"));
183 }
184 Lua53 => {
185 config
186 .file(source_dir.join("lbitlib.c"))
187 .file(source_dir.join("lcorolib.c"))
188 .file(source_dir.join("lctype.c"))
189 .file(source_dir.join("lutf8lib.c"));
190 }
191 Lua54 => {
192 config
193 .file(source_dir.join("lcorolib.c"))
194 .file(source_dir.join("lctype.c"))
195 .file(source_dir.join("lutf8lib.c"));
196 }
197 }
198
199 config.out_dir(&lib_dir).compile(lib_name);
200
201 for f in &["lauxlib.h", "lua.h", "luaconf.h", "lualib.h"] {
202 fs::copy(source_dir.join(f), include_dir.join(f)).unwrap();
203 }
204
205 if let LuaFactorio52 = version {
206 fs::copy(source_dir.join("lua.hpp"), include_dir.join("lua.hpp")).unwrap();
207 }
208
209 Artifacts {
210 lib_dir,
211 include_dir,
212 libs: vec![lib_name.to_string()],
213 }
214 }
215}
216
217impl Artifacts {
218 pub fn include_dir(&self) -> &Path {
219 &self.include_dir
220 }
221
222 pub fn lib_dir(&self) -> &Path {
223 &self.lib_dir
224 }
225
226 pub fn libs(&self) -> &[String] {
227 &self.libs
228 }
229
230 pub fn print_cargo_metadata(&self) {
231 println!("cargo:rustc-link-search=native={}", self.lib_dir.display());
232 for lib in self.libs.iter() {
233 println!("cargo:rustc-link-lib=static={}", lib);
234 }
235 println!("cargo:include={}", self.include_dir.display());
236 println!("cargo:lib={}", self.lib_dir.display());
237 }
238}