1 #![allow(clippy::option_if_let_else)]
6 use std::process::{Command, ExitStatus, Stdio};
9 #[cfg(all(feature = "backtrace", not(feature = "std")))]
11 "`backtrace` feature without `std` feature is not supported"
14 // This code exercises the surface area that we expect of the std Backtrace
15 // type. If the current toolchain is able to compile it, we go ahead and use
16 // backtrace in anyhow.
17 const PROBE: &str = r#"
18 #![feature(error_generic_member_access, provide_any)]
20 use std::any::{Demand, Provider};
21 use std::backtrace::{Backtrace, BacktraceStatus};
22 use std::error::Error;
23 use std::fmt::{self, Display};
31 fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
37 fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
38 demand.provide_ref(&self.backtrace);
45 fn provide<'a>(&'a self, _demand: &mut Demand<'a>) {}
49 let backtrace: Backtrace = Backtrace::capture();
50 let status: BacktraceStatus = backtrace.status();
52 BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
56 const _: fn(&dyn Error) -> Option<&Backtrace> = |err| err.request_ref::<Backtrace>();
60 if cfg!(feature = "std") {
61 match compile_probe() {
62 Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
67 let rustc = match rustc_minor_version() {
73 println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
77 println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str");
81 fn compile_probe() -> Option<ExitStatus> {
82 let rustc = env::var_os("RUSTC")?;
83 let out_dir = env::var_os("OUT_DIR")?;
84 let probefile = Path::new(&out_dir).join("probe.rs");
85 fs::write(&probefile, PROBE).ok()?;
87 // Make sure to pick up Cargo rustc configuration.
88 let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
89 let mut cmd = Command::new(wrapper);
90 // The wrapper's first argument is supposed to be the path to rustc.
97 cmd.stderr(Stdio::null())
98 .arg("--edition=2018")
99 .arg("--crate-name=anyhow_build")
100 .arg("--crate-type=lib")
101 .arg("--emit=metadata")
106 if let Some(target) = env::var_os("TARGET") {
107 cmd.arg("--target").arg(target);
110 // If Cargo wants to set RUSTFLAGS, use that.
111 if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") {
112 if !rustflags.is_empty() {
113 for arg in rustflags.split('\x1f') {
122 fn rustc_minor_version() -> Option<u32> {
123 let rustc = env::var_os("RUSTC")?;
124 let output = Command::new(rustc).arg("--version").output().ok()?;
125 let version = str::from_utf8(&output.stdout).ok()?;
126 let mut pieces = version.split('.');
127 if pieces.next() != Some("rustc 1") {
130 pieces.next()?.parse().ok()