aboutsummaryrefslogtreecommitdiff
path: root/build.rs
diff options
context:
space:
mode:
Diffstat (limited to 'build.rs')
-rw-r--r--build.rs134
1 files changed, 85 insertions, 49 deletions
diff --git a/build.rs b/build.rs
index fc585cf..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,45 +9,53 @@ compile_error! {
"`backtrace` feature without `std` feature is not supported"
}
-// This code exercises the surface area that we expect of the Error generic
-// member access API. If the current toolchain is able to compile it, then
-// anyhow is able to provide backtrace support.
-const PROBE: &str = r#"
- #![feature(error_generic_member_access)]
-
- use std::backtrace::Backtrace;
- use std::error::{self, Error, Request};
- use std::fmt::{self, Debug, Display};
-
- struct MyError(Thing);
- struct Thing;
-
- impl Debug for MyError {
- fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
- unimplemented!()
- }
- }
-
- impl Display for MyError {
- 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 MyError {
- fn provide<'a>(&'a self, request: &mut Request<'a>) {
- request.provide_ref(&self.0);
+ if error_generic_member_access {
+ println!("cargo:rustc-cfg=std_backtrace");
+ println!("cargo:rustc-cfg=error_generic_member_access");
}
- }
- const _: fn(&dyn Error) -> Option<&Backtrace> = |err| error::request_ref::<Backtrace>(err);
-"#;
-
-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");
}
}
@@ -59,15 +65,29 @@ 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> {
+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:
@@ -76,13 +96,12 @@ fn compile_probe() -> Option<ExitStatus> {
// https://github.com/rust-lang/rust/issues/114839
//
// Let's just not use nightly features here.
- return None;
+ return false;
}
- 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()?;
+ 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);
+ })
+}