factorio_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.cpp(true).define("USE_LUA_PACKAGE", None);
130        }
131
132        config
133            .include(&source_dir)
134            .flag("-w") // Suppress all warnings
135            .flag_if_supported("-fno-common") // Compile common globals like normal definitions
136            .file(source_dir.join("lapi.c"))
137            .file(source_dir.join("lauxlib.c"))
138            .file(source_dir.join("lbaselib.c"))
139            // skipped: lbitlib.c (>= 5.2, <= 5.3)
140            .file(source_dir.join("lcode.c"))
141            // skipped: lcorolib.c (>= 5.2)
142            // skipped: lctype.c (>= 5.2)
143            .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            // skipped: lutf8lib.c (>= 5.3)
167            .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}