boringssl_src/
lib.rs

1use std::env;
2use std::fs;
3use std::path::{Path, PathBuf};
4use std::process::Command;
5
6pub fn source_dir() -> PathBuf {
7    Path::new(env!("CARGO_MANIFEST_DIR")).join("boringssl")
8}
9
10pub struct Build {
11    out_dir: Option<PathBuf>,
12    msvc: bool,
13}
14
15pub struct Artifacts {
16    root_dir: PathBuf,
17    libs: Vec<String>,
18}
19
20impl Default for Build {
21    #[inline]
22    fn default() -> Build {
23        Build {
24            out_dir: env::var_os("OUT_DIR").map(|s| PathBuf::from(s).join("boringssl-build")),
25            msvc: env::var("TARGET").map_or(false, |t| t.contains("msvc")),
26        }
27    }
28}
29
30impl Build {
31    pub fn new() -> Build {
32        Build::default()
33    }
34
35    pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Build {
36        self.out_dir = Some(path.as_ref().to_path_buf());
37        self
38    }
39
40    fn configure_asm_support(&self, cfg: &mut cmake::Config) {
41        if !self.msvc {
42            return;
43        }
44
45        let output = Command::new("cmake")
46            .arg("--version")
47            .output()
48            .expect("Can't find cmake.");
49        let output = String::from_utf8_lossy(&output.stdout);
50        let uptodate = output.split_whitespace().nth(2).map_or(false, |version| {
51            let vers: Vec<u32> = match version.split('.').map(|n| n.parse()).collect() {
52                Ok(v) => v,
53                Err(_) => return false,
54            };
55            // Visual Studio build with assembly optimizations is broken for older version of cmake
56            vers.len() == 3 && vers[0] >= 3 && vers[1] >= 13
57        });
58        if uptodate {
59            let check_exist = |cmd, arg| {
60                Command::new(cmd)
61                    .arg(arg)
62                    .status()
63                    .map_or(false, |s| s.success())
64            };
65            if check_exist("yasm", "--version") || check_exist("nasm", "-v") {
66                return;
67            }
68        }
69
70        cfg.define("OPENSSL_NO_ASM", "ON");
71    }
72
73    pub fn build(&mut self) -> Artifacts {
74        let out_dir = self.out_dir.as_ref().expect("OUT_DIR not set");
75
76        let build_dir = out_dir.join("build");
77        if build_dir.exists() {
78            fs::remove_dir_all(&build_dir).unwrap();
79        }
80        fs::create_dir_all(&build_dir).unwrap();
81
82        let mut cfg = cmake::Config::new(source_dir());
83        self.configure_asm_support(&mut cfg);
84        cfg.out_dir(&out_dir);
85        cfg.build_target("ssl").build();
86        cfg.build_target("crypto").build();
87
88        let header_dir = out_dir.join("include");
89        if header_dir.exists() {
90            fs::remove_dir_all(&header_dir).unwrap();
91        }
92        fs::create_dir_all(&header_dir).unwrap();
93
94        let include_dir = source_dir().join("src").join("include");
95        cp_r(&include_dir, &header_dir);
96
97        let lib_dir = out_dir.join("lib");
98        if lib_dir.exists() {
99            fs::remove_dir_all(&lib_dir).unwrap();
100        }
101        let from_dir = if self.msvc {
102            let profile = cfg.get_profile();
103            build_dir.join(profile)
104        } else {
105            build_dir
106        };
107        fs::rename(&from_dir, &lib_dir).unwrap();
108
109        Artifacts {
110            root_dir: self.out_dir.clone().unwrap(),
111            libs: vec!["ssl".to_string(), "crypto".to_string()],
112        }
113    }
114}
115
116fn cp_r(src: impl AsRef<Path>, dst: impl AsRef<Path>) {
117    for f in fs::read_dir(src.as_ref()).unwrap() {
118        let f = f.unwrap();
119        let path = f.path();
120        let name = path.file_name().unwrap();
121
122        // Skip git metadata as it's been known to cause issues (#26) and
123        // otherwise shouldn't be required
124        if name.to_str() == Some(".git") {
125            continue;
126        }
127
128        let dst = dst.as_ref().join(name);
129        if f.file_type().unwrap().is_dir() {
130            fs::create_dir_all(&dst).unwrap();
131            cp_r(&path, &dst);
132        } else {
133            let _ = fs::remove_file(&dst);
134            fs::copy(&path, &dst).unwrap();
135        }
136    }
137}
138
139impl Artifacts {
140    pub fn include_dir(&self) -> PathBuf {
141        self.root_dir.join("include")
142    }
143
144    pub fn lib_dir(&self) -> PathBuf {
145        self.root_dir.join("lib")
146    }
147
148    pub fn root_dir(&self) -> &Path {
149        &self.root_dir
150    }
151
152    pub fn libs(&self) -> &[String] {
153        &self.libs
154    }
155
156    pub fn print_cargo_metadata(&self) {
157        println!(
158            "cargo:rustc-link-search=native={}",
159            self.lib_dir().display()
160        );
161        for lib in self.libs.iter() {
162            println!("cargo:rustc-link-lib=static={}", lib);
163        }
164        println!("cargo:include={}", self.include_dir().display());
165        println!("cargo:lib={}", self.lib_dir().display());
166    }
167}