gmssl_src/
lib.rs

1extern crate cc;
2
3use std::env;
4use std::ffi::OsStr;
5use std::fs;
6use std::path::{Path, PathBuf};
7use std::process::Command;
8
9pub fn source_dir() -> PathBuf {
10    Path::new(env!("CARGO_MANIFEST_DIR")).join("gmssl")
11}
12
13pub fn version() -> &'static str {
14    env!("CARGO_PKG_VERSION")
15}
16
17pub struct Build {
18    out_dir: Option<PathBuf>,
19    target: Option<String>,
20    host: Option<String>,
21}
22
23pub struct Artifacts {
24    include_dir: PathBuf,
25    lib_dir: PathBuf,
26    bin_dir: PathBuf,
27    libs: Vec<String>,
28    target: String,
29}
30
31impl Build {
32    pub fn new() -> Build {
33        Build {
34            out_dir: env::var_os("OUT_DIR").map(|s| PathBuf::from(s).join("gmssl-build")),
35            target: env::var("TARGET").ok(),
36            host: env::var("HOST").ok(),
37        }
38    }
39
40    pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Build {
41        self.out_dir = Some(path.as_ref().to_path_buf());
42        self
43    }
44
45    pub fn target(&mut self, target: &str) -> &mut Build {
46        self.target = Some(target.to_string());
47        self
48    }
49
50    pub fn host(&mut self, host: &str) -> &mut Build {
51        self.host = Some(host.to_string());
52        self
53    }
54
55    fn cmd_make(&self) -> Command {
56        let host = &self.host.as_ref().expect("HOST dir not set")[..];
57        if host.contains("dragonfly")
58            || host.contains("freebsd")
59            || host.contains("openbsd")
60            || host.contains("solaris")
61            || host.contains("illumos")
62        {
63            Command::new("gmake")
64        } else {
65            Command::new("make")
66        }
67    }
68
69
70    fn cmd_cmake(&self) -> Command {
71            Command::new("cmake")
72    }
73
74    #[cfg(windows)]
75    fn check_env_var(&self, var_name: &str) -> Option<bool> {
76        env::var_os(var_name).map(|s| {
77            if s == "1" {
78                // a message to stdout, let user know asm is force enabled
79                println!(
80                    "{}: nasm.exe is force enabled by the \
81                    'OPENSSL_RUST_USE_NASM' env var.",
82                    env!("CARGO_PKG_NAME")
83                );
84                true
85            } else if s == "0" {
86                // a message to stdout, let user know asm is force disabled
87                println!(
88                    "{}: nasm.exe is force disabled by the \
89                    'OPENSSL_RUST_USE_NASM' env var.",
90                    env!("CARGO_PKG_NAME")
91                );
92                false
93            } else {
94                panic!(
95                    "The environment variable {} is set to an unacceptable value: {:?}",
96                    var_name, s
97                );
98            }
99        })
100    }
101
102    #[cfg(windows)]
103    fn is_nasm_ready(&self) -> bool {
104        self.check_env_var("OPENSSL_RUST_USE_NASM")
105            .unwrap_or_else(|| {
106                // On Windows, use cmd `where` command to check if nasm is installed
107                let wherenasm = Command::new("cmd")
108                    .args(&["/C", "where nasm"])
109                    .output()
110                    .expect("Failed to execute `cmd`.");
111                wherenasm.status.success()
112            })
113    }
114
115    #[cfg(not(windows))]
116    fn is_nasm_ready(&self) -> bool {
117        // We assume that nobody would run nasm.exe on a non-windows system.
118        false
119    }
120
121    pub fn build(&mut self) -> Artifacts {
122        let target = &self.target.as_ref().expect("TARGET dir not set")[..];
123
124
125
126        let host = &self.host.as_ref().expect("HOST dir not set")[..];
127        let out_dir = self.out_dir.as_ref().expect("OUT_DIR not set");
128
129        self.run_command(Command::new("ls"),format!("{:?}",out_dir).as_str());
130        
131        let build_dir = out_dir.join("build");
132      
133
134        let install_dir = out_dir.join("install");
135
136        if build_dir.exists() {
137            fs::remove_dir_all(&build_dir).unwrap();
138        }
139        if install_dir.exists() {
140            fs::remove_dir_all(&install_dir).unwrap();
141        }
142
143        let inner_dir = build_dir.join("src");
144        fs::create_dir_all(&inner_dir).unwrap();
145        cp_r(&source_dir(), &inner_dir);
146
147        let mut ls_src = Command::new("ls");
148        ls_src.arg(&inner_dir);
149        self.run_command(ls_src,"display_target");
150
151        let mut display_target = Command::new("echo");
152        display_target.arg(&source_dir());
153        display_target.arg(&inner_dir);
154        display_target.arg(&build_dir);
155        display_target.arg(&install_dir);
156        self.run_command(display_target,"display_target");
157        
158        // And finally, run the perl configure script!
159
160        //self.run_command(configure, "configuring OpenSSL build");
161
162        // On MSVC we use `nmake.exe` with a slightly different invocation, so
163        // have that take a different path than the standard `make` below.
164        if target.contains("msvc") {
165            let mut build =
166                cc::windows_registry::find(target, "nmake.exe").expect("failed to find nmake");
167            build.arg("build_libs").current_dir(&inner_dir);
168            self.run_command(build, "building OpenSSL");
169
170            let mut install =
171                cc::windows_registry::find(target, "nmake.exe").expect("failed to find nmake");
172            install.arg("install_dev").current_dir(&inner_dir);
173            self.run_command(install, "installing OpenSSL");
174        } else {
175
176            let mut depend = self.cmd_cmake();
177            depend.arg("src").current_dir(&build_dir);
178            let path = install_dir.as_path().to_str().unwrap();
179            depend.arg(format!("-DCMAKE_INSTALL_PREFIX={}",path));
180
181            self.run_command(depend, "building OpenSSL dependencies");
182
183            let mut build = self.cmd_make();
184            build.current_dir(&build_dir);
185            if !cfg!(windows) {
186                if let Some(s) = env::var_os("CARGO_MAKEFLAGS") {
187                    build.env("MAKEFLAGS", s);
188                }
189            }
190
191/* 
192            if let Some(ref isysr) = ios_isysroot {
193                let components: Vec<&str> = isysr.split("/SDKs/").collect();
194                build.env("CROSS_TOP", components[0]);
195                build.env("CROSS_SDK", components[1]);
196            }
197*/
198
199            self.run_command(build, "building OpenSSL");
200
201            let mut install = self.cmd_make();
202            install.arg("install").current_dir(&build_dir);
203            self.run_command(install, "installing OpenSSL");
204        }
205
206        let libs = if target.contains("msvc") {
207            vec!["libssl".to_string(), "libcrypto".to_string()]
208        } else {
209            vec!["gmssl".to_string()]
210        };
211
212        fs::remove_dir_all(&inner_dir).unwrap();
213
214        Artifacts {
215            lib_dir: install_dir.join("lib"),
216            bin_dir: install_dir.join("bin"),
217            include_dir: install_dir.join("include"),
218            libs: libs,
219            target: target.to_string(),
220        }
221    }
222
223    fn run_command(&self, mut command: Command, desc: &str) {
224        println!("running {:?}", command);
225        let status = command.status();
226
227        let (status_or_failed, error) = match status {
228            Ok(status) if status.success() => return,
229            Ok(status) => ("Exit status", format!("{}", status)),
230            Err(failed) => ("Failed to execute", format!("{}", failed)),
231        };
232        panic!(
233            "
234
235
236Error {}:
237    Command: {:?}
238    {}: {}
239
240
241    ",
242            desc, command, status_or_failed, error
243        );
244    }
245}
246
247fn cp_r(src: &Path, dst: &Path) {
248    for f in fs::read_dir(src).unwrap() {
249        let f = f.unwrap();
250        let path = f.path();
251        let name = path.file_name().unwrap();
252
253        // Skip git metadata as it's been known to cause issues (#26) and
254        // otherwise shouldn't be required
255        if name.to_str() == Some(".git") {
256            continue;
257        }
258
259        let dst = dst.join(name);
260        if f.file_type().unwrap().is_dir() {
261            fs::create_dir_all(&dst).unwrap();
262            cp_r(&path, &dst);
263        } else {
264            let _ = fs::remove_file(&dst);
265            fs::copy(&path, &dst).unwrap();
266        }
267    }
268}
269
270fn sanitize_sh(path: &Path) -> String {
271    if !cfg!(windows) {
272        return path.to_str().unwrap().to_string();
273    }
274    let path = path.to_str().unwrap().replace("\\", "/");
275    return change_drive(&path).unwrap_or(path);
276
277    fn change_drive(s: &str) -> Option<String> {
278        let mut ch = s.chars();
279        let drive = ch.next().unwrap_or('C');
280        if ch.next() != Some(':') {
281            return None;
282        }
283        if ch.next() != Some('/') {
284            return None;
285        }
286        Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
287    }
288}
289
290impl Artifacts {
291    pub fn include_dir(&self) -> &Path {
292        &self.include_dir
293    }
294
295    pub fn lib_dir(&self) -> &Path {
296        &self.lib_dir
297    }
298
299    pub fn libs(&self) -> &[String] {
300        &self.libs
301    }
302
303    pub fn print_cargo_metadata(&self) {
304        println!("cargo:rustc-link-search=native={}", self.lib_dir.display());
305        for lib in self.libs.iter() {
306            println!("cargo:rustc-link-lib={}", lib);
307        }
308        println!("cargo:include={}", self.include_dir.display());
309        println!("cargo:lib={}", self.lib_dir.display());
310        if self.target.contains("msvc") {
311            println!("cargo:rustc-link-lib=user32");
312        } else if self.target == "wasm32-wasi" {
313            println!("cargo:rustc-link-lib=wasi-emulated-signal");
314            println!("cargo:rustc-link-lib=wasi-emulated-process-clocks");
315            println!("cargo:rustc-link-lib=wasi-emulated-mman");
316            println!("cargo:rustc-link-lib=wasi-emulated-getpid");
317        }
318    }
319}