aboutsummaryrefslogtreecommitdiff
path: root/build.rs
diff options
context:
space:
mode:
Diffstat (limited to 'build.rs')
-rw-r--r--build.rs154
1 files changed, 95 insertions, 59 deletions
diff --git a/build.rs b/build.rs
index 3800683..7e95e6b 100644
--- a/build.rs
+++ b/build.rs
@@ -1,9 +1,7 @@
-#![allow(clippy::option_if_let_else)]
-
use std::env;
-use std::fs;
+use std::ffi::OsString;
use std::path::Path;
-use std::process::{Command, ExitStatus, Stdio};
+use std::process::{self, Command, Stdio};
use std::str;
#[cfg(all(feature = "backtrace", not(feature = "std")))]
@@ -11,56 +9,53 @@ compile_error! {
"`backtrace` feature without `std` feature is not supported"
}
-// 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(error_generic_member_access, provide_any)]
-
- use std::any::{Demand, Provider};
- use std::backtrace::{Backtrace, BacktraceStatus};
- use std::error::Error;
- use std::fmt::{self, Display};
-
- #[derive(Debug)]
- struct E {
- backtrace: Backtrace,
- }
-
- impl Display for E {
- fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
- unimplemented!()
+fn main() {
+ let mut error_generic_member_access = false;
+ if cfg!(feature = "std") {
+ println!("cargo:rerun-if-changed=build/probe.rs");
+
+ let consider_rustc_bootstrap;
+ if compile_probe(false) {
+ // This is a nightly or dev compiler, so it supports unstable
+ // features regardless of RUSTC_BOOTSTRAP. No need to rerun build
+ // script if RUSTC_BOOTSTRAP is changed.
+ error_generic_member_access = true;
+ consider_rustc_bootstrap = false;
+ } else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") {
+ if compile_probe(true) {
+ // This is a stable or beta compiler for which the user has set
+ // RUSTC_BOOTSTRAP to turn on unstable features. Rerun build
+ // script if they change it.
+ error_generic_member_access = true;
+ consider_rustc_bootstrap = true;
+ } else if rustc_bootstrap == "1" {
+ // This compiler does not support the generic member access API
+ // in the form that anyhow expects. No need to pay attention to
+ // RUSTC_BOOTSTRAP.
+ error_generic_member_access = false;
+ consider_rustc_bootstrap = false;
+ } else {
+ // This is a stable or beta compiler for which RUSTC_BOOTSTRAP
+ // is set to restrict the use of unstable features by this
+ // crate.
+ error_generic_member_access = false;
+ consider_rustc_bootstrap = true;
+ }
+ } else {
+ // Without RUSTC_BOOTSTRAP, this compiler does not support the
+ // generic member access API in the form that anyhow expects, but
+ // try again if the user turns on unstable features.
+ error_generic_member_access = false;
+ consider_rustc_bootstrap = true;
}
- }
- impl Error for E {
- fn provide<'a>(&'a self, demand: &mut Demand<'a>) {
- demand.provide_ref(&self.backtrace);
+ if error_generic_member_access {
+ println!("cargo:rustc-cfg=std_backtrace");
+ println!("cargo:rustc-cfg=error_generic_member_access");
}
- }
- struct P;
-
- impl Provider for P {
- fn provide<'a>(&'a self, _demand: &mut Demand<'a>) {}
- }
-
- const _: fn() = || {
- let backtrace: Backtrace = Backtrace::capture();
- let status: BacktraceStatus = backtrace.status();
- match status {
- BacktraceStatus::Captured | BacktraceStatus::Disabled | _ => {}
- }
- };
-
- const _: fn(&dyn Error) -> Option<&Backtrace> = |err| err.request_ref::<Backtrace>();
-"#;
-
-fn main() {
- if cfg!(feature = "std") {
- match compile_probe() {
- Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
- _ => {}
+ if consider_rustc_bootstrap {
+ println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP");
}
}
@@ -70,19 +65,43 @@ fn main() {
};
if rustc < 51 {
+ // core::ptr::addr_of
+ // https://blog.rust-lang.org/2021/03/25/Rust-1.51.0.html#stabilized-apis
println!("cargo:rustc-cfg=anyhow_no_ptr_addr_of");
}
if rustc < 52 {
+ // core::fmt::Arguments::as_str
+ // https://blog.rust-lang.org/2021/05/06/Rust-1.52.0.html#stabilized-apis
println!("cargo:rustc-cfg=anyhow_no_fmt_arguments_as_str");
+
+ // #![deny(unsafe_op_in_unsafe_fn)]
+ // https://github.com/rust-lang/rust/issues/71668
+ println!("cargo:rustc-cfg=anyhow_no_unsafe_op_in_unsafe_fn_lint");
+ }
+
+ if !error_generic_member_access && cfg!(feature = "std") && rustc >= 65 {
+ // std::backtrace::Backtrace
+ // https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html#stabilized-apis
+ println!("cargo:rustc-cfg=std_backtrace");
}
}
-fn compile_probe() -> Option<ExitStatus> {
- let rustc = env::var_os("RUSTC")?;
- let out_dir = env::var_os("OUT_DIR")?;
- let probefile = Path::new(&out_dir).join("probe.rs");
- fs::write(&probefile, PROBE).ok()?;
+fn compile_probe(rustc_bootstrap: bool) -> bool {
+ if env::var_os("RUSTC_STAGE").is_some() {
+ // We are running inside rustc bootstrap. This is a highly non-standard
+ // environment with issues such as:
+ //
+ // https://github.com/rust-lang/cargo/issues/11138
+ // https://github.com/rust-lang/rust/issues/114839
+ //
+ // Let's just not use nightly features here.
+ return false;
+ }
+
+ let rustc = cargo_env_var("RUSTC");
+ let out_dir = cargo_env_var("OUT_DIR");
+ let probefile = Path::new("build").join("probe.rs");
// Make sure to pick up Cargo rustc configuration.
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") {
@@ -94,11 +113,15 @@ fn compile_probe() -> Option<ExitStatus> {
Command::new(rustc)
};
+ if !rustc_bootstrap {
+ cmd.env_remove("RUSTC_BOOTSTRAP");
+ }
+
cmd.stderr(Stdio::null())
.arg("--edition=2018")
- .arg("--crate-name=anyhow_build")
+ .arg("--crate-name=anyhow")
.arg("--crate-type=lib")
- .arg("--emit=metadata")
+ .arg("--emit=dep-info,metadata")
.arg("--out-dir")
.arg(out_dir)
.arg(probefile);
@@ -116,11 +139,14 @@ fn compile_probe() -> Option<ExitStatus> {
}
}
- cmd.status().ok()
+ match cmd.status() {
+ Ok(status) => status.success(),
+ Err(_) => false,
+ }
}
fn rustc_minor_version() -> Option<u32> {
- let rustc = env::var_os("RUSTC")?;
+ let rustc = cargo_env_var("RUSTC");
let output = Command::new(rustc).arg("--version").output().ok()?;
let version = str::from_utf8(&output.stdout).ok()?;
let mut pieces = version.split('.');
@@ -129,3 +155,13 @@ fn rustc_minor_version() -> Option<u32> {
}
pieces.next()?.parse().ok()
}
+
+fn cargo_env_var(key: &str) -> OsString {
+ env::var_os(key).unwrap_or_else(|| {
+ eprintln!(
+ "Environment variable ${} is not set during execution of build script",
+ key,
+ );
+ process::exit(1);
+ })
+}