1extern crate cc;
2
3use std::env;
4use std::ffi::{OsStr, OsString};
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("openssl")
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 openssl_dir: Option<PathBuf>,
23}
24
25pub struct Artifacts {
26 include_dir: PathBuf,
27 lib_dir: PathBuf,
28 bin_dir: PathBuf,
29 libs: Vec<String>,
30 target: String,
31}
32
33impl Build {
34 pub fn new() -> Build {
35 Build {
36 out_dir: env::var_os("OUT_DIR").map(|s| PathBuf::from(s).join("openssl-build")),
37 target: env::var("TARGET").ok(),
38 host: env::var("HOST").ok(),
39 openssl_dir: Some(PathBuf::from("/usr/local/ssl")),
40 }
41 }
42
43 pub fn out_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Build {
44 self.out_dir = Some(path.as_ref().to_path_buf());
45 self
46 }
47
48 pub fn target(&mut self, target: &str) -> &mut Build {
49 self.target = Some(target.to_string());
50 self
51 }
52
53 pub fn host(&mut self, host: &str) -> &mut Build {
54 self.host = Some(host.to_string());
55 self
56 }
57
58 pub fn openssl_dir<P: AsRef<Path>>(&mut self, path: P) -> &mut Build {
59 self.openssl_dir = Some(path.as_ref().to_path_buf());
60 self
61 }
62
63 fn cmd_make(&self) -> Result<Command, &'static str> {
64 let host = &self.host.as_ref().ok_or("HOST dir not set")?[..];
65 Ok(
66 if host.contains("dragonfly")
67 || host.contains("freebsd")
68 || host.contains("openbsd")
69 || host.contains("solaris")
70 || host.contains("illumos")
71 {
72 Command::new("gmake")
73 } else {
74 Command::new("make")
75 },
76 )
77 }
78
79 #[cfg(windows)]
80 fn check_env_var(&self, var_name: &str) -> Option<bool> {
81 env::var_os(var_name).and_then(|s| {
82 if s == "1" {
83 println!(
85 "cargo:warning={}: nasm.exe is force enabled by the \
86 'OPENSSL_RUST_USE_NASM' env var.",
87 env!("CARGO_PKG_NAME")
88 );
89 Some(true)
90 } else if s == "0" {
91 println!(
93 "cargo:warning={}: nasm.exe is force disabled by the \
94 'OPENSSL_RUST_USE_NASM' env var.",
95 env!("CARGO_PKG_NAME")
96 );
97 Some(false)
98 } else {
99 println!(
100 "cargo:warning=The environment variable {} is set to an unacceptable value: {:?}",
101 var_name, s
102 );
103 None
104 }
105 })
106 }
107
108 #[cfg(windows)]
109 fn is_nasm_ready(&self) -> bool {
110 self.check_env_var("OPENSSL_RUST_USE_NASM")
111 .unwrap_or_else(|| {
112 Command::new("cmd")
114 .args(&["/C", "where nasm"])
115 .output()
116 .map(|w| w.status.success())
117 .unwrap_or(false)
118 })
119 }
120
121 #[cfg(not(windows))]
122 fn is_nasm_ready(&self) -> bool {
123 false
125 }
126
127 pub fn build(&mut self) -> Artifacts {
129 match self.try_build() {
130 Ok(a) => a,
131 Err(e) => {
132 println!("cargo:warning=openssl-src: failed to build OpenSSL from source");
133 eprintln!("\n\n\n{e}\n\n\n");
134 std::process::exit(1);
135 }
136 }
137 }
138
139 pub fn try_build(&mut self) -> Result<Artifacts, String> {
140 let target = &self.target.as_ref().ok_or("TARGET dir not set")?[..];
141 let host = &self.host.as_ref().ok_or("HOST dir not set")?[..];
142 let out_dir = self.out_dir.as_ref().ok_or("OUT_DIR not set")?;
143 let build_dir = out_dir.join("build");
144 let install_dir = out_dir.join("install");
145
146 if build_dir.exists() {
147 fs::remove_dir_all(&build_dir).map_err(|e| format!("build_dir: {e}"))?;
148 }
149 if install_dir.exists() {
150 fs::remove_dir_all(&install_dir).map_err(|e| format!("install_dir: {e}"))?;
151 }
152
153 let inner_dir = build_dir.join("src");
154 fs::create_dir_all(&inner_dir).map_err(|e| format!("{}: {e}", inner_dir.display()))?;
155 cp_r(&source_dir(), &inner_dir)?;
156
157 let perl_program =
158 env::var("OPENSSL_SRC_PERL").unwrap_or(env::var("PERL").unwrap_or("perl".to_string()));
159 let mut configure = Command::new(perl_program);
160 configure.arg("./Configure");
161
162 if host.contains("pc-windows-gnu") {
164 configure.arg(&format!("--prefix={}", sanitize_sh(&install_dir)));
165 } else if host.contains("pc-windows-msvc") || host.contains("win7-windows-msvc") {
166 configure.arg(&format!(
171 "--prefix={}",
172 install_dir
173 .to_str()
174 .ok_or("bad install_dir")?
175 .replace("\\", "/")
176 ));
177 } else {
178 configure.arg(&format!("--prefix={}", install_dir.display()));
179 }
180
181 if target.contains("windows") {
186 configure.arg("--openssldir=SYS$MANAGER:[OPENSSL]");
187 } else {
188 let openssl_dir = self
189 .openssl_dir
190 .as_ref()
191 .ok_or("path to the openssl directory must be set")?;
192 let mut dir_arg: OsString = "--openssldir=".into();
193 dir_arg.push(openssl_dir);
194 configure.arg(dir_arg);
195 }
196
197 configure
198 .arg("no-shared")
200 .arg("no-module")
201 .arg("no-tests")
203 .arg("no-comp")
205 .arg("no-zlib")
206 .arg("no-zlib-dynamic")
207 .arg("--libdir=lib");
209
210 if cfg!(feature = "no-dso") {
211 if cfg!(feature = "force-engine") {
213 println!("Feature 'force-engine' requires DSO, ignoring 'no-dso' feature.");
214 } else {
215 configure.arg("no-dso");
216 }
217 }
218
219 if cfg!(not(feature = "legacy")) {
220 configure.arg("no-legacy");
221 }
222
223 if cfg!(feature = "ssl3") {
224 configure.arg("enable-ssl3").arg("enable-ssl3-method");
225 } else {
226 configure.arg("no-ssl3");
228 }
229
230 if cfg!(feature = "weak-crypto") {
231 configure
232 .arg("enable-md2")
233 .arg("enable-rc5")
234 .arg("enable-weak-ssl-ciphers");
235 } else {
236 configure
237 .arg("no-md2")
238 .arg("no-rc5")
239 .arg("no-weak-ssl-ciphers");
240 }
241
242 if cfg!(not(feature = "camellia")) {
243 configure.arg("no-camellia");
244 }
245
246 if cfg!(not(feature = "idea")) {
247 configure.arg("no-idea");
248 }
249
250 if cfg!(not(feature = "seed")) {
251 configure.arg("no-seed");
252 }
253
254 if cfg!(feature = "ktls") {
255 configure.arg("enable-ktls");
256 }
257
258 if target.contains("musl") {
259 if !cfg!(feature = "force-engine") {
263 configure.arg("no-engine");
264 }
265 } else if target.contains("windows") {
266 configure.arg("no-capieng");
271 }
272
273 if target.contains("musl") {
274 configure.arg("no-async");
277 }
278
279 if target.contains("android") {
283 configure.arg("no-stdio");
284 }
285
286 if target.contains("msvc") {
287 if self.is_nasm_ready() {
291 println!(
293 "{}: Enable the assembly language routines in building OpenSSL.",
294 env!("CARGO_PKG_NAME")
295 );
296 } else {
297 configure.arg("no-asm");
298 }
299 }
300
301 let os = match target {
302 "aarch64-apple-darwin" => "darwin64-arm64-cc",
303 "aarch64-linux-android" => "linux-aarch64",
309 "aarch64-unknown-freebsd" => "BSD-generic64",
310 "aarch64-unknown-openbsd" => "BSD-generic64",
311 "aarch64-unknown-linux-gnu" => "linux-aarch64",
312 "aarch64-unknown-linux-musl" => "linux-aarch64",
313 "aarch64-alpine-linux-musl" => "linux-aarch64",
314 "aarch64-chimera-linux-musl" => "linux-aarch64",
315 "aarch64-unknown-netbsd" => "BSD-generic64",
316 "aarch64_be-unknown-netbsd" => "BSD-generic64",
317 "aarch64-pc-windows-msvc" => "VC-WIN64-ARM",
318 "aarch64-uwp-windows-msvc" => "VC-WIN64-ARM-UWP",
319 "arm-linux-androideabi" => "linux-armv4",
320 "armv7-linux-androideabi" => "linux-armv4",
321 "arm-unknown-linux-gnueabi" => "linux-armv4",
322 "arm-unknown-linux-gnueabihf" => "linux-armv4",
323 "arm-unknown-linux-musleabi" => "linux-armv4",
324 "arm-unknown-linux-musleabihf" => "linux-armv4",
325 "arm-chimera-linux-musleabihf" => "linux-armv4",
326 "armv5te-unknown-linux-gnueabi" => "linux-armv4",
327 "armv5te-unknown-linux-musleabi" => "linux-armv4",
328 "armv6-unknown-freebsd" => "BSD-generic32",
329 "armv6-alpine-linux-musleabihf" => "linux-armv6",
330 "armv7-unknown-freebsd" => "BSD-armv4",
331 "armv7-unknown-linux-gnueabi" => "linux-armv4",
332 "armv7-unknown-linux-musleabi" => "linux-armv4",
333 "armv7-unknown-linux-gnueabihf" => "linux-armv4",
334 "armv7-unknown-linux-musleabihf" => "linux-armv4",
335 "armv7-alpine-linux-musleabihf" => "linux-armv4",
336 "armv7-chimera-linux-musleabihf" => "linux-armv4",
337 "armv7-unknown-netbsd-eabihf" => "BSD-generic32",
338 "asmjs-unknown-emscripten" => "gcc",
339 "i586-unknown-linux-gnu" => "linux-elf",
340 "i586-unknown-linux-musl" => "linux-elf",
341 "i586-alpine-linux-musl" => "linux-elf",
342 "i586-unknown-netbsd" => "BSD-x86-elf",
343 "i686-apple-darwin" => "darwin-i386-cc",
344 "i686-linux-android" => "linux-elf",
345 "i686-pc-windows-gnu" => "mingw",
346 "i686-pc-windows-msvc" => "VC-WIN32",
347 "i686-win7-windows-msvc" => "VC-WIN32",
348 "i686-unknown-freebsd" => "BSD-x86-elf",
349 "i686-unknown-haiku" => "haiku-x86",
350 "i686-unknown-linux-gnu" => "linux-elf",
351 "i686-unknown-linux-musl" => "linux-elf",
352 "i686-unknown-netbsd" => "BSD-x86-elf",
353 "i686-uwp-windows-msvc" => "VC-WIN32-UWP",
354 "loongarch64-unknown-linux-gnu" => "linux-generic64",
355 "loongarch64-unknown-linux-musl" => "linux-generic64",
356 "mips-unknown-linux-gnu" => "linux-mips32",
357 "mips-unknown-linux-musl" => "linux-mips32",
358 "mips64-unknown-linux-gnuabi64" => "linux64-mips64",
359 "mips64-unknown-linux-muslabi64" => "linux64-mips64",
360 "mips64-openwrt-linux-musl" => "linux64-mips64",
361 "mips64el-unknown-linux-gnuabi64" => "linux64-mips64",
362 "mips64el-unknown-linux-muslabi64" => "linux64-mips64",
363 "mipsel-unknown-linux-gnu" => "linux-mips32",
364 "mipsel-unknown-linux-musl" => "linux-mips32",
365 "powerpc-unknown-freebsd" => "BSD-ppc",
366 "powerpc-unknown-linux-gnu" => "linux-ppc",
367 "powerpc-unknown-linux-gnuspe" => "linux-ppc",
368 "powerpc-chimera-linux-musl" => "linux-ppc",
369 "powerpc-unknown-netbsd" => "BSD-generic32",
370 "powerpc64-unknown-freebsd" => "BSD-ppc64",
371 "powerpc64-unknown-linux-gnu" => "linux-ppc64",
372 "powerpc64-unknown-linux-gnuelfv2" => "linux-ppc64",
373 "powerpc64-unknown-linux-musl" => "linux-ppc64",
374 "powerpc64-chimera-linux-musl" => "linux-ppc64",
375 "powerpc64le-unknown-freebsd" => "BSD-ppc64le",
376 "powerpc64le-unknown-linux-gnu" => "linux-ppc64le",
377 "powerpc64le-unknown-linux-musl" => "linux-ppc64le",
378 "powerpc64le-alpine-linux-musl" => "linux-ppc64le",
379 "powerpc64le-chimera-linux-musl" => "linux-ppc64le",
380 "riscv64gc-unknown-freebsd" => "BSD-riscv64",
381 "riscv64a23-unknown-linux-gnu" => "linux64-riscv64",
382 "riscv64gc-unknown-linux-gnu" => "linux64-riscv64",
383 "riscv64gc-unknown-linux-musl" => "linux64-riscv64",
384 "riscv64-alpine-linux-musl" => "linux64-riscv64",
385 "riscv64-chimera-linux-musl" => "linux64-riscv64",
386 "riscv64gc-unknown-netbsd" => "BSD-generic64",
387 "s390x-unknown-linux-gnu" => "linux64-s390x",
388 "sparc64-unknown-netbsd" => "BSD-generic64",
389 "sparc64-unknown-linux-gnu" => "linux64-sparcv9",
390 "s390x-unknown-linux-musl" => "linux64-s390x",
391 "s390x-alpine-linux-musl" => "linux64-s390x",
392 "sparcv9-sun-solaris" => "solaris64-sparcv9-gcc",
393 "thumbv7a-uwp-windows-msvc" => "VC-WIN32-ARM-UWP",
394 "x86_64-apple-darwin" => "darwin64-x86_64-cc",
395 "x86_64-linux-android" => "linux-x86_64",
396 "x86_64-linux" => "linux-x86_64",
397 "x86_64-pc-windows-gnu" => "mingw64",
398 "x86_64-pc-windows-gnullvm" => "mingw64",
399 "x86_64-pc-windows-msvc" => "VC-WIN64A",
400 "x86_64-win7-windows-msvc" => "VC-WIN64A",
401 "x86_64-unknown-freebsd" => "BSD-x86_64",
402 "x86_64-unknown-dragonfly" => "BSD-x86_64",
403 "x86_64-unknown-haiku" => "haiku-x86_64",
404 "x86_64-unknown-illumos" => "solaris64-x86_64-gcc",
405 "x86_64-unknown-linux-gnu" => "linux-x86_64",
406 "x86_64-unknown-linux-musl" => "linux-x86_64",
407 "x86_64-alpine-linux-musl" => "linux-x86_64",
408 "x86_64-chimera-linux-musl" => "linux-x86_64",
409 "x86_64-unknown-openbsd" => "BSD-x86_64",
410 "x86_64-unknown-netbsd" => "BSD-x86_64",
411 "x86_64-uwp-windows-msvc" => "VC-WIN64A-UWP",
412 "x86_64-pc-solaris" => "solaris64-x86_64-gcc",
413 "wasm32-unknown-emscripten" => "gcc",
414 "wasm32-unknown-unknown" => "gcc",
415 "wasm32-wasi" => "gcc",
416 "aarch64-apple-ios" => "ios64-cross",
417 "aarch64-apple-visionos" => "ios64-cross",
418 "x86_64-apple-ios" => "iossimulator-x86_64-xcrun",
419 "aarch64-apple-ios-sim" => "iossimulator-arm64-xcrun",
420 "aarch64-apple-visionos-sim" => "iossimulator-arm64-xcrun",
421 "aarch64-apple-ios-macabi" => "darwin64-arm64-cc",
422 "x86_64-apple-ios-macabi" => "darwin64-x86_64-cc",
423 "aarch64-unknown-linux-ohos" => "linux-aarch64",
424 "armv7-unknown-linux-ohos" => "linux-generic32",
425 "x86_64-unknown-linux-ohos" => "linux-x86_64",
426 _ => {
427 return Err(format!(
428 "don't know how to configure OpenSSL for {}",
429 target
430 ))
431 }
432 };
433
434 let mut ios_isysroot: std::option::Option<String> = None;
435
436 configure.arg(os);
437
438 if !target.contains("msvc") {
442 let mut cc = cc::Build::new();
443 cc.target(target).host(host).warnings(false).opt_level(2);
444 let compiler = cc.get_compiler();
445 let mut cc_env = compiler.cc_env();
446 if cc_env.is_empty() {
447 cc_env = compiler.path().to_path_buf().into_os_string();
448 }
449 configure.env("CC", cc_env);
450 let path = compiler.path().to_str().ok_or("compiler path")?;
451
452 configure.env_remove("CROSS_COMPILE");
456
457 let ar = cc.get_archiver();
458 configure.env("AR", ar.get_program());
459 if ar.get_args().count() != 0 {
460 configure.env(
464 "ARFLAGS",
465 ar.get_args().collect::<Vec<_>>().join(OsStr::new(" ")),
466 );
467 }
468 let ranlib = cc.get_ranlib();
469 let mut args = vec![ranlib.get_program()];
471 args.extend(ranlib.get_args());
472 configure.env("RANLIB", args.join(OsStr::new(" ")));
473
474 let mut skip_next = false;
477 let mut is_isysroot = false;
478 for arg in compiler.args() {
479 if target.contains("musl") && arg == "-static" {
482 continue;
483 }
484
485 if target.contains("apple") {
489 if arg == "-arch" {
490 skip_next = true;
491 continue;
492 }
493 }
494
495 if target.contains("apple-ios") || target.contains("apple-visionos") {
497 if arg == "-isysroot" {
498 is_isysroot = true;
499 continue;
500 }
501
502 if is_isysroot {
503 is_isysroot = false;
504 ios_isysroot = Some(arg.to_str().ok_or("isysroot arg")?.to_string());
505 continue;
506 }
507 }
508
509 if skip_next {
510 skip_next = false;
511 continue;
512 }
513
514 configure.arg(arg);
515 }
516
517 if target == "aarch64-apple-visionos" {
518 if let Some(ref isysr) = ios_isysroot {
519 configure.env(
520 "CC",
521 &format!(
522 "xcrun -sdk xros cc -isysroot {}",
523 sanitize_sh(&Path::new(isysr))
524 ),
525 );
526 }
527 } else if target == "aarch64-apple-visionos-sim" {
528 if let Some(ref isysr) = ios_isysroot {
529 configure.env(
530 "CC",
531 &format!(
532 "xcrun -sdk xrsimulator cc -isysroot {}",
533 sanitize_sh(&Path::new(isysr))
534 ),
535 );
536 }
537 } else if os.contains("iossimulator") {
538 if let Some(ref isysr) = ios_isysroot {
539 configure.env(
540 "CC",
541 &format!(
542 "xcrun -sdk iphonesimulator cc -isysroot {}",
543 sanitize_sh(&Path::new(isysr))
544 ),
545 );
546 }
547 }
548
549 if target == "x86_64-pc-windows-gnu" {
550 configure.arg("-Wa,-mbig-obj");
565 }
566
567 if target.contains("pc-windows-gnu") && path.ends_with("-gcc") {
568 let windres = format!("{}-windres", &path[..path.len() - 4]);
573 configure.env("WINDRES", &windres);
574
575 if !cfg!(windows) {
579 configure.arg("no-quic");
580 }
581 }
582
583 if target.contains("emscripten") {
584 configure.arg("-D__STDC_NO_ATOMICS__");
591 }
592
593 if target.contains("wasi") {
594 configure.args([
595 "no-ui-console",
597 "no-sock",
599 "-DNO_SYSLOG",
601 "no-threads",
603 "no-asm",
605 "no-afalgeng",
609 "-DOPENSSL_NO_AFALGENG=1",
610 "-D_WASI_EMULATED_SIGNAL",
614 "-D_WASI_EMULATED_PROCESS_CLOCKS",
619 "-D_WASI_EMULATED_MMAN",
623 "-D_WASI_EMULATED_GETPID",
628 "-DNO_CHMOD",
630 ]);
631 }
632
633 if target.contains("musl") {
634 configure.arg("-DOPENSSL_NO_SECURE_MEMORY");
636 }
637 }
638
639 configure.current_dir(&inner_dir);
641 self.run_command(configure, "configuring OpenSSL build")?;
642
643 if target.contains("msvc") {
646 let mut build =
647 cc::windows_registry::find(target, "nmake.exe").ok_or("failed to find nmake")?;
648 build.arg("build_libs").current_dir(&inner_dir);
649 self.run_command(build, "building OpenSSL")?;
650
651 let mut install =
652 cc::windows_registry::find(target, "nmake.exe").ok_or("failed to find nmake")?;
653 install.arg("install_dev").current_dir(&inner_dir);
654 self.run_command(install, "installing OpenSSL")?;
655 } else {
656 let mut depend = self.cmd_make()?;
657 depend.arg("depend").current_dir(&inner_dir);
658 self.run_command(depend, "building OpenSSL dependencies")?;
659
660 let mut build = self.cmd_make()?;
661 build.arg("build_libs").current_dir(&inner_dir);
662 if !cfg!(windows) {
663 if let Some(s) = env::var_os("CARGO_MAKEFLAGS") {
664 build.env("MAKEFLAGS", s);
665 }
666 }
667
668 if let Some(ref isysr) = ios_isysroot {
669 let components: Vec<&str> = isysr.split("/SDKs/").collect();
670 build.env("CROSS_TOP", components[0]);
671 build.env("CROSS_SDK", components[1]);
672 }
673
674 self.run_command(build, "building OpenSSL")?;
675
676 let mut install = self.cmd_make()?;
677 install.arg("install_dev").current_dir(&inner_dir);
678 self.run_command(install, "installing OpenSSL")?;
679 }
680
681 let libs = if target.contains("msvc") {
682 vec!["libssl".to_string(), "libcrypto".to_string()]
683 } else {
684 vec!["ssl".to_string(), "crypto".to_string()]
685 };
686
687 fs::remove_dir_all(&inner_dir).map_err(|e| format!("{}: {e}", inner_dir.display()))?;
688
689 Ok(Artifacts {
690 lib_dir: install_dir.join("lib"),
691 bin_dir: install_dir.join("bin"),
692 include_dir: install_dir.join("include"),
693 libs: libs,
694 target: target.to_string(),
695 })
696 }
697
698 #[track_caller]
699 fn run_command(&self, mut command: Command, desc: &str) -> Result<(), String> {
700 println!("running {:?}", command);
701 let status = command.status();
702
703 let verbose_error = match status {
704 Ok(status) if status.success() => return Ok(()),
705 Ok(status) => format!(
706 "'{exe}' reported failure with {status}",
707 exe = command.get_program().to_string_lossy()
708 ),
709 Err(failed) => match failed.kind() {
710 std::io::ErrorKind::NotFound => format!(
711 "Command '{exe}' not found. Is {exe} installed?",
712 exe = command.get_program().to_string_lossy()
713 ),
714 _ => format!(
715 "Could not run '{exe}', because {failed}",
716 exe = command.get_program().to_string_lossy()
717 ),
718 },
719 };
720 println!("cargo:warning={desc}: {verbose_error}");
721 Err(format!(
722 "Error {desc}:
723 {verbose_error}
724 Command failed: {command:?}"
725 ))
726 }
727}
728
729fn cp_r(src: &Path, dst: &Path) -> Result<(), String> {
730 for f in fs::read_dir(src).map_err(|e| format!("{}: {e}", src.display()))? {
731 let f = match f {
732 Ok(f) => f,
733 _ => continue,
734 };
735 let path = f.path();
736 let name = path
737 .file_name()
738 .ok_or_else(|| format!("bad dir {}", src.display()))?;
739
740 if name.to_str() == Some(".git") {
743 continue;
744 }
745
746 let dst = dst.join(name);
747 let ty = f.file_type().map_err(|e| e.to_string())?;
748 if ty.is_dir() {
749 fs::create_dir_all(&dst).map_err(|e| e.to_string())?;
750 cp_r(&path, &dst)?;
751 } else if ty.is_symlink() && path.iter().any(|p| p == "cloudflare-quiche") {
752 continue;
754 } else {
755 let _ = fs::remove_file(&dst);
756 if let Err(e) = fs::copy(&path, &dst) {
757 return Err(format!(
758 "failed to copy '{}' to '{}': {e}",
759 path.display(),
760 dst.display()
761 ));
762 }
763 }
764 }
765 Ok(())
766}
767
768fn sanitize_sh(path: &Path) -> String {
769 if !cfg!(windows) {
770 return path.to_string_lossy().into_owned();
771 }
772 let path = path.to_string_lossy().replace("\\", "/");
773 return change_drive(&path).unwrap_or(path);
774
775 fn change_drive(s: &str) -> Option<String> {
776 let mut ch = s.chars();
777 let drive = ch.next().unwrap_or('C');
778 if ch.next() != Some(':') {
779 return None;
780 }
781 if ch.next() != Some('/') {
782 return None;
783 }
784 Some(format!("/{}/{}", drive, &s[drive.len_utf8() + 2..]))
785 }
786}
787
788const TARGETS_NEEDING_LATOMIC: &[&str] = &[
791 "arm-linux-androideabi",
793 "armv7-linux-androideabi",
794 "arm-unknown-linux-gnueabi",
795 "arm-unknown-linux-gnueabihf",
796 "arm-unknown-linux-musleabi",
797 "arm-unknown-linux-musleabihf",
798 "arm-chimera-linux-musleabihf",
799 "armv5te-unknown-linux-gnueabi",
800 "armv5te-unknown-linux-musleabi",
801 "armv7-unknown-linux-gnueabi",
802 "armv7-unknown-linux-musleabi",
803 "armv7-unknown-linux-gnueabihf",
804 "armv7-unknown-linux-musleabihf",
805 "armv7-alpine-linux-musleabihf",
806 "armv7-chimera-linux-musleabihf",
807 "mips-unknown-linux-gnu",
809 "mips-unknown-linux-musl",
810 "mipsel-unknown-linux-gnu",
811 "mipsel-unknown-linux-musl",
812 "powerpc-unknown-linux-gnu",
814 "powerpc-unknown-linux-gnuspe",
815 "powerpc-chimera-linux-musl",
816 "sparc64-unknown-linux-gnu",
818];
819
820impl Artifacts {
821 pub fn include_dir(&self) -> &Path {
822 &self.include_dir
823 }
824
825 pub fn lib_dir(&self) -> &Path {
826 &self.lib_dir
827 }
828
829 pub fn libs(&self) -> &[String] {
830 &self.libs
831 }
832
833 pub fn needs_latomic(&self) -> bool {
834 TARGETS_NEEDING_LATOMIC.contains(&self.target.as_str())
835 }
836
837 pub fn print_cargo_metadata(&self) {
838 println!("cargo:rustc-link-search=native={}", self.lib_dir.display());
839 for lib in self.libs.iter() {
840 println!("cargo:rustc-link-lib=static={}", lib);
841 }
842 if self.needs_latomic() {
843 println!("cargo:rustc-link-lib=atomic");
844 }
845 println!("cargo:include={}", self.include_dir.display());
846 println!("cargo:lib={}", self.lib_dir.display());
847 if self.target.contains("windows") {
848 println!("cargo:rustc-link-lib=user32");
849 println!("cargo:rustc-link-lib=crypt32");
850 println!("cargo:rustc-link-lib=advapi32");
851 } else if self.target == "wasm32-wasi" {
852 println!("cargo:rustc-link-lib=wasi-emulated-signal");
853 println!("cargo:rustc-link-lib=wasi-emulated-process-clocks");
854 println!("cargo:rustc-link-lib=wasi-emulated-mman");
855 println!("cargo:rustc-link-lib=wasi-emulated-getpid");
856 }
857 }
858}