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 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(¤t_work_dir).unwrap();
135
136 let source_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("TASSL");
137 cp_r(&source_dir, ¤t_work_dir);
138
139 let mut chmod = Command::new("chmod");
140 chmod.current_dir(¤t_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(¤t_work_dir);
146 run_command(configure, "configuring TASSL");
147
148 let mut build = Command::new("make");
149 build.current_dir(¤t_work_dir);
150 run_command(build, "building TASSL");
151
152 let mut install = Command::new("make");
153 install.arg("install").current_dir(¤t_work_dir);
154 run_command(install, "installing TASSL");
155
156 fs::remove_dir_all(¤t_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}