tassl_src/
lib.rs

1use std::{env, fs, path::{Path, PathBuf}, process::Command};
2
3fn run_command(mut command: Command, desc: &str) {
4    println!("running {:?}", command);
5    let status = command.status().unwrap();
6    if !status.success() {
7        panic!(
8            "
9Error {}:
10    Command: {:?}
11    Exit status: {}
12    ",
13            desc, command, status
14        );
15    }
16}
17
18fn cp_r(src: &Path, dst: &Path) {
19    for f in fs::read_dir(src).unwrap() {
20        let f = f.unwrap();
21        let path = f.path();
22        let name = path.file_name().unwrap();
23
24        // Skip git metadata as it's been known to cause issues (#26) and
25        // otherwise shouldn't be required
26        if name.to_str() == Some(".git") {
27            continue;
28        }
29
30        let dst = dst.join(name);
31        if f.file_type().unwrap().is_dir() {
32            fs::create_dir_all(&dst).unwrap();
33            cp_r(&path, &dst);
34        } else {
35            let _ = fs::remove_file(&dst);
36            fs::copy(&path, &dst).unwrap();
37        }
38    }
39}
40
41
42pub struct Artifacts {
43    pub include_dir: PathBuf,
44    pub lib_dir: PathBuf,
45    pub bin_dir: PathBuf,
46    pub libs: Vec<String>,
47}
48
49impl Artifacts {
50    pub fn print_cargo_metadata(&self) {
51        println!("cargo:rustc-link-search=native={}", self.lib_dir.display());
52        for lib in self.libs.iter() {
53            println!("cargo:rustc-link-lib=static={}", lib);
54        }
55        println!("cargo:include={}", self.include_dir.display());
56        println!("cargo:lib={}", self.lib_dir.display());
57    }
58}
59
60pub struct Builder {
61    build_dir: PathBuf,
62    install_dir: PathBuf,
63    target: String,
64    is_force: bool,
65}
66
67impl Builder {
68    pub fn default() -> Builder {
69        let out_dir = env::var_os("OUT_DIR").unwrap().into_string().unwrap();
70        let target = env::var("TARGET").ok().unwrap();
71        Builder::new(&out_dir, &target, false)
72    }
73
74    pub fn new(out_dir: &str, target: &str, is_force: bool) -> Builder {
75        let base_dir = PathBuf::from(out_dir.to_owned()).join("tassl-build");
76        Builder {
77            build_dir: base_dir.join("build"),
78            install_dir: base_dir.join("install"),
79            target: target.to_owned(),
80            is_force
81        }
82    }
83
84    #[cfg(target_os = "linux")]
85    fn get_configure(&self) -> Command {
86        let mut configure = Command::new("sh");
87        configure.arg("./config");
88        configure.arg(&format!("--prefix={}", self.install_dir.display()));
89        configure.arg("-DOPENSSL_PIC");
90        configure.arg("no-shared");
91        configure
92    }
93
94    #[cfg(target_os = "macos")]
95    fn get_configure(&self) -> Command {
96        let mut configure = Command::new("sh");
97        configure.arg("./Configure");
98        configure.arg(&format!("--prefix={}", self.install_dir.display()));
99        let os = match self.target.as_str() {
100            "aarch64-apple-darwin" => "darwin64-arm64-cc",
101            "i686-apple-darwin" => "darwin-i386-cc",
102            "x86_64-apple-darwin" => "darwin64-x86_64-cc",
103            _ => panic!("Don't know how to configure TASSL for {}", &self.target),
104        };
105        configure.arg(os);
106        configure
107    }
108
109    #[cfg(all(not(target_os = "macos"), not(target_os = "linux")))]
110    pub fn build(&self) -> Artifacts {
111        panic!("Not support {:?} yet.", self.target);
112    }
113
114    #[cfg(any(target_os = "macos", target_os = "linux"))]
115    pub fn build(&self) -> Artifacts {
116        if self.install_dir.exists() {
117            if self.is_force {
118                fs::remove_dir_all(&self.install_dir).unwrap();
119            } else {
120                return Artifacts {
121                    lib_dir: self.install_dir.join("lib"),
122                    bin_dir: self.install_dir.join("bin"),
123                    include_dir: self.install_dir.join("include"),
124                    libs: vec!["ssl".to_string(), "crypto".to_string()],
125                };
126            }
127        }
128
129        if self.build_dir.exists() {
130            fs::remove_dir_all(&self.build_dir).unwrap();
131        }
132
133        let current_work_dir = self.build_dir.join("src");
134        fs::create_dir_all(&current_work_dir).unwrap();
135
136        let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("TASSL");
137        cp_r(&source_dir, &current_work_dir);
138
139        let mut chmod = Command::new("chmod");
140        chmod.current_dir(&current_work_dir);
141        chmod.arg("-R").arg("a+x").arg("./util");
142        run_command(chmod, "change TASSL util permission");
143
144        let mut configure = self.get_configure();
145        configure.current_dir(&current_work_dir);
146        run_command(configure, "configuring TASSL");
147
148        let mut build = Command::new("make");
149        build.current_dir(&current_work_dir);
150        run_command(build, "building TASSL");
151
152        let mut install = Command::new("make");
153        install.arg("install").current_dir(&current_work_dir);
154        run_command(install, "installing TASSL");
155
156        fs::remove_dir_all(&current_work_dir).unwrap();
157        Artifacts {
158            lib_dir: self.install_dir.join("lib"),
159            bin_dir: self.install_dir.join("bin"),
160            include_dir: self.install_dir.join("include"),
161            libs: vec!["ssl".to_string(), "crypto".to_string()],
162        }
163    }
164}