theseus_lua_src/
lib.rs

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                // Defined in Lua >= 5.3
106                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") // Suppress all warnings
138            .flag_if_supported("-fno-common") // Compile common globals like normal definitions
139            .file(source_dir.join("lapi.c"))
140            .file(source_dir.join("lauxlib.c"))
141            .file(source_dir.join("lbaselib.c"))
142            // skipped: lbitlib.c (>= 5.2, <= 5.3)
143            .file(source_dir.join("lcode.c"))
144            // skipped: lcorolib.c (>= 5.2)
145            // skipped: lctype.c (>= 5.2)
146            .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            // skipped: lutf8lib.c (>= 5.3)
170            .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}