From 5ada2978c5841dc5d043acdf99a9ac69ff88e527 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 18 Oct 2019 10:43:43 -0400 Subject: [PATCH] Replace version check with probing Backtrace api --- build.rs | 78 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 27 deletions(-) diff --git a/build.rs b/build.rs index 7f59c64..862fb7a 100644 --- a/build.rs +++ b/build.rs @@ -1,35 +1,59 @@ use std::env; -use std::process::Command; -use std::str::{self, FromStr}; +use std::fs; +use std::path::Path; +use std::process::{Command, ExitStatus}; + +// This code exercises the surface area that we expect of the std Backtrace +// type. If the current toolchain is able to compile it, we go ahead and use +// backtrace in anyhow. +const PROBE: &str = r#" + #![feature(backtrace)] + #![allow(dead_code)] + + use std::backtrace::{Backtrace, BacktraceStatus}; + use std::error::Error; + use std::fmt::{self, Display}; + + #[derive(Debug)] + struct E; + + impl Display for E { + fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result { + unimplemented!() + } + } + + impl Error for E { + fn backtrace(&self) -> Option<&Backtrace> { + let backtrace = Backtrace::capture(); + match backtrace.status() { + BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {} + } + unimplemented!() + } + } +"#; fn main() { - let compiler = match rustc_version() { - Some(compiler) => compiler, - None => return, - }; - - if compiler.minor >= 40 && compiler.nightly { - println!("cargo:rustc-cfg=backtrace"); + match compile_probe() { + Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"), + _ => {} } } -struct Compiler { - minor: u32, - nightly: bool, -} - -fn rustc_version() -> Option { +fn compile_probe() -> Option { let rustc = env::var_os("RUSTC")?; - let output = Command::new(rustc).arg("--version").output().ok()?; - let version = str::from_utf8(&output.stdout).ok()?; - - let mut pieces = version.split('.'); - if pieces.next() != Some("rustc 1") { - return None; - } - - let next = pieces.next()?; - let minor = u32::from_str(next).ok()?; - let nightly = version.contains("nightly") || version.contains("dev"); - Some(Compiler { minor, nightly }) + let out_dir = env::var_os("OUT_DIR")?; + let probefile = Path::new(&out_dir).join("lib.rs"); + fs::write(&probefile, PROBE).ok()?; + Command::new(rustc) + .arg("--edition=2018") + .arg("--crate-name=anyhow_build") + .arg("--crate-type=lib") + .arg("--emit=metadata") + .arg("--out-dir") + .arg(out_dir) + .arg(probefile) + .status() + .ok() }