File: build.rs

package info (click to toggle)
rust-eyre 0.6.12-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 388 kB
  • sloc: makefile: 2
file content (132 lines) | stat: -rw-r--r-- 3,605 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::Path;
use std::process::{Command, ExitStatus};
use std::str;

// 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 eyre.
const BACKTRACE_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!()
        }
    }
"#;

const TRACK_CALLER_PROBE: &str = r#"
    #![allow(dead_code)]

    #[track_caller]
    fn foo() {
        let _location = std::panic::Location::caller();
    }
"#;

fn main() {
    match compile_probe(BACKTRACE_PROBE) {
        Some(status) if status.success() => println!("cargo:rustc-cfg=backtrace"),
        _ => {}
    }

    match compile_probe(TRACK_CALLER_PROBE) {
        Some(status) if status.success() => println!("cargo:rustc-cfg=track_caller"),
        _ => {}
    }

    let version = match rustc_version_info() {
        Some(version) => version,
        None => return,
    };

    version.toolchain.set_feature();

    if version.minor < 52 {
        println!("cargo:rustc-cfg=eyre_no_fmt_arguments_as_str");
    }

    if version.minor < 58 {
        println!("cargo:rustc-cfg=eyre_no_fmt_args_capture");
    }
}

fn compile_probe(probe: &str) -> 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()?;
    Command::new(rustc)
        .arg("--edition=2018")
        .arg("--crate-name=eyre_build")
        .arg("--crate-type=lib")
        .arg("--emit=metadata")
        .arg("--out-dir")
        .arg(out_dir)
        .arg(probefile)
        .status()
        .ok()
}

// TODO factor this toolchain parsing and related tests into its own file
#[derive(PartialEq)]
enum Toolchain {
    Stable,
    Beta,
    Nightly,
}
impl Toolchain {
    fn set_feature(self) {
        match self {
            Toolchain::Nightly => println!("cargo:rustc-cfg=nightly"),
            Toolchain::Beta => println!("cargo:rustc-cfg=beta"),
            Toolchain::Stable => println!("cargo:rustc-cfg=stable"),
        }
    }
}

struct VersionInfo {
    minor: u32,
    toolchain: Toolchain,
}

fn rustc_version_info() -> Option<VersionInfo> {
    let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
    let output = Command::new(rustc).arg("--version").output().ok()?;
    let version = str::from_utf8(&output.stdout).ok()?.trim();
    let mut pieces = version.split(['.', ' ', '-']);
    if pieces.next() != Some("rustc") {
        return None;
    }
    let _major: u32 = pieces.next()?.parse().ok()?;
    let minor = pieces.next()?.parse().ok()?;
    let _patch: u32 = pieces.next()?.parse().ok()?;
    let toolchain = match pieces.next() {
        Some("beta") => Toolchain::Beta,
        Some("nightly") => Toolchain::Nightly,
        _ => Toolchain::Stable,
    };
    let version = VersionInfo { minor, toolchain };
    Some(version)
}