1use cc::Build;
2use std::env;
3use std::ffi::OsStr;
4use std::fs;
5use std::path::{Path, PathBuf};
6use std::process::Command;
7
8fn is_modified(static_lib_path: &PathBuf, folder: &str) -> std::io::Result<bool> {
9 let lib_meta = fs::metadata(static_lib_path)?;
10 let lib_age = lib_meta.modified()?;
11 if let Ok(lib_age) = lib_age.elapsed() {
12 let dir_iter = fs::read_dir(folder)?;
13 for entry in dir_iter {
14 if let Ok(entry) = entry {
15 if let Ok(md) = entry.metadata() {
16 if let Ok(file_age) = md.modified() {
17 if let Ok(file_age) = file_age.elapsed() {
18 if file_age < lib_age {
19 return Ok(true);
20 }
21 }
22 }
23 }
24 }
25 }
26 } else {
27 return Ok(true);
28 }
29 Ok(false)
30}
31
32pub fn build(folder: &str, add_start: bool, appname: &str) -> std::io::Result<()> {
41 let target = env::var("TARGET").unwrap();
42 let out_dir_s = std::env::var("OUT_DIR").unwrap();
43 let out_dir = Path::new(&out_dir_s);
44 let static_lib_path = out_dir.join("libwxrs.a");
45 let wxcfg = env::var("WX_CONFIG").unwrap_or("wx-config".to_owned());
46 let wxdir = env::var("WX_DIR").unwrap_or("".to_owned());
47
48 if is_modified(&static_lib_path, folder).unwrap_or(true) {
49 let mut cc = Build::new();
50 for entry in fs::read_dir(folder)? {
51 let entry = entry?;
52 let path = entry.path();
53 let extension = path.extension().and_then(OsStr::to_str).unwrap_or("");
54 if extension == "cpp" {
55 cc.file(&path);
56 }
57 }
58 if let Ok(cxx) = Command::new(wxcfg.as_str()).args(&["--cxxflags"]).output() {
59 let cxx = std::str::from_utf8(cxx.stdout.as_ref()).unwrap();
60 for word in cxx.split_whitespace() {
61 cc.flag(word);
62 }
63 } else if wxdir.len() > 0 && target.contains("msvc") {
64 cc.define("__WXMSW__", "1");
65 cc.define("_UNICODE", "1");
66 cc.include(Path::new(&wxdir).join("include"));
67 cc.include(Path::new(&wxdir).join("include").join("msvc"));
68 } else {
70 panic!("No WX_CONFIG or WX_DIR set");
71 }
72 cc.cpp(true);
73 if target.contains("darwin") {
74 cc.flag("-mmacosx-version-min=10.12");
75 cc.flag("-std=c++11");
76 } else if target.contains("msvc") {
77 cc.flag("/EHsc");
78 }
79 if add_start {
80 cc.include(folder);
81 let start = out_dir.join("start.cpp");
82 let mut file = fs::File::create(start.clone()).unwrap();
83 use std::io::Write;
84 let cpp = format!("#include <wx/wx.h>\n
85 #include \"{}.h\"
86 wxIMPLEMENT_APP_NO_MAIN({});
87 extern \"C\" {{ void wx_start() {{ char **argv = nullptr; int argc = 0; wxEntry(argc, argv); }} }}", appname.to_ascii_lowercase(), appname);
88 file.write(cpp.as_bytes()).unwrap();
89 cc.file(start);
90
91 let mut file = fs::File::create(&out_dir.join("wxffi.rs")).unwrap();
92 file.write(
93 br#"
94 pub fn start() {
95 unsafe {
96 wx_start();
97 }
98 }
99 extern "C" {
100 fn wx_start();
101 }
102 "#,
103 )
104 .unwrap();
105 }
107
108 cc.extra_warnings(false);
109 cc.compile("libwxrs.a");
110 }
111
112 println!("cargo:rustc-link-search=native={}", out_dir_s);
113 println!("cargo:rustc-link-lib=wxrs");
114
115 if wxdir.len() > 0 && target.contains("msvc") {
116 println!("cargo:rustc-link-search=native={}\\lib\\vc_x64_lib", wxdir);
117 let dir_iter = fs::read_dir(Path::new(&wxdir).join("lib").join("vc_x64_lib"))?;
122 for entry in dir_iter {
123 if let Ok(entry) = entry {
124 let path = entry.path();
125 let extension = path.extension().and_then(OsStr::to_str).unwrap_or("");
126 let file_stem = path.file_stem().and_then(OsStr::to_str).unwrap_or("");
127 if extension == "lib" {
128 if file_stem.starts_with("wxmsw31ud") {
139 continue;
140 } else if file_stem.starts_with("wxbase31ud") {
141 continue;
142 } else if file_stem.starts_with("wxmsw31u") {
143 println!("cargo:rustc-link-lib=static={}", file_stem);
144 } else if file_stem.starts_with("wxbase31u") {
145 println!("cargo:rustc-link-lib=static={}", file_stem);
146 } else if !file_stem.ends_with("d") {
147 println!("cargo:rustc-link-lib=static={}", file_stem);
148 }
149 }
151 }
152 }
153 return Ok(());
154 }
155
156 let libs = Command::new(wxcfg.as_str())
157 .args(&["--libs"])
158 .output()
159 .expect("failed to execute wx-config");
160 let libs = std::str::from_utf8(libs.stdout.as_ref()).unwrap();
161 let mut framework: bool = false;
162 for part in libs.split_whitespace() {
163 if part.starts_with("-L") {
164 println!(
165 "cargo:rustc-link-search=native={}",
166 part.trim_start_matches("-L")
167 );
168 } else if part.starts_with("-l") {
169 let static_pth = format!("/usr/local/lib/lib{}.a", part.trim_start_matches("-l"));
170 if fs::metadata(static_pth).is_ok() {
171 println!("cargo:rustc-link-search=native=/usr/local/lib/");
172 println!(
173 "cargo:rustc-link-lib=static={}",
174 part.trim_start_matches("-l")
175 );
176 } else {
177 println!("cargo:rustc-link-lib={}", part.trim_start_matches("-l"));
178 }
179 } else if part == "-framework" {
180 framework = true;
181 } else {
182 if framework {
183 println!("cargo:rustc-link-lib=framework={}", part);
184 framework = false;
185 } else if part.ends_with(".a") {
186 let path = PathBuf::from(part.to_string());
187 println!(
188 "cargo:rustc-link-search=native={}",
189 path.parent().unwrap().to_str().unwrap()
190 );
191 println!(
192 "cargo:rustc-link-lib={}",
193 path.file_stem()
194 .unwrap()
195 .to_str()
196 .unwrap()
197 .trim_start_matches("lib")
198 );
199 }
200 }
201 }
202 println!("cargo:rustc-link-lib=c++");
203
204 Ok(())
205}