94 lines
3.9 KiB
Rust
94 lines
3.9 KiB
Rust
const MAX_USED_VERSION: u64 = 80;
|
|
|
|
use std::io;
|
|
|
|
fn main() {
|
|
let rustc = std::env::var_os("RUSTC");
|
|
let rustc = rustc.as_ref().map(std::path::Path::new).unwrap_or_else(|| "rustc".as_ref());
|
|
let output = std::process::Command::new(rustc)
|
|
.arg("--version")
|
|
.output()
|
|
.unwrap_or_else(|error| panic!("failed to run `{:?} --version`: {:?}", rustc, error));
|
|
assert!(output.status.success(), "{:?} -- version returned non-zero exit code", rustc);
|
|
let stdout = String::from_utf8(output.stdout).expect("rustc produced non-UTF-8 output");
|
|
let version_prefix = "rustc ";
|
|
if !stdout.starts_with(version_prefix) {
|
|
panic!("unexpected rustc output: {}", stdout);
|
|
}
|
|
|
|
let version = &stdout[version_prefix.len()..];
|
|
let end = version.find(&[' ', '-'] as &[_]).unwrap_or(version.len());
|
|
let version = &version[..end];
|
|
let mut version_components = version.split('.');
|
|
let major = version_components.next().unwrap();
|
|
assert_eq!(major, "1", "unexpected Rust major version");
|
|
let minor = version_components
|
|
.next()
|
|
.unwrap_or("0")
|
|
.parse::<u64>()
|
|
.expect("invalid Rust minor version");
|
|
|
|
let msrv = std::env::var("CARGO_PKG_RUST_VERSION").unwrap();
|
|
let mut msrv = msrv.split(".");
|
|
let msrv_major = msrv.next().unwrap();
|
|
assert_eq!(msrv_major, "1", "unexpected Rust major version");
|
|
let msrv_minor = msrv.next().unwrap().parse::<u64>().unwrap();
|
|
|
|
let out_dir = std::env::var_os("OUT_DIR").expect("missing OUT_DIR env var");
|
|
let out_dir = std::path::PathBuf::from(out_dir);
|
|
let macro_file = std::fs::File::create(out_dir.join("rust_version.rs"))
|
|
.expect("failed to create rust_version.rs");
|
|
let macro_file = io::BufWriter::new(macro_file);
|
|
write_macro(macro_file, msrv_minor, minor).expect("failed to write to rust_version.rs");
|
|
}
|
|
|
|
fn write_macro(mut macro_file: impl io::Write, msrv_minor: u64, minor: u64) -> io::Result<()> {
|
|
writeln!(macro_file, "/// Expands code based on Rust version this is compiled under.")?;
|
|
writeln!(macro_file, "///")?;
|
|
writeln!(macro_file, "/// Example:")?;
|
|
writeln!(macro_file, "/// ```")?;
|
|
writeln!(macro_file, "/// bitcoin_internals::rust_version! {{")?;
|
|
writeln!(macro_file, "/// if >= 1.70 {{")?;
|
|
writeln!(macro_file, "/// println!(\"This is Rust 1.70+\");")?;
|
|
writeln!(macro_file, "/// }} else {{")?;
|
|
writeln!(macro_file, "/// println!(\"This is Rust < 1.70\");")?;
|
|
writeln!(macro_file, "/// }}")?;
|
|
writeln!(macro_file, "/// }}")?;
|
|
writeln!(macro_file, "/// ```")?;
|
|
writeln!(macro_file, "///")?;
|
|
writeln!(macro_file, "/// The `else` branch is optional.")?;
|
|
writeln!(macro_file, "/// Currently only the `>=` operator is supported.")?;
|
|
writeln!(macro_file, "#[macro_export]")?;
|
|
writeln!(macro_file, "macro_rules! rust_version {{")?;
|
|
|
|
// These two loops are the magic; we output the clause if_yes/if_no
|
|
// dependent on the current compiler version (`minor`).
|
|
for version in msrv_minor..=minor {
|
|
writeln!(
|
|
macro_file,
|
|
" (if >= 1.{} {{ $($if_yes:tt)* }} $(else {{ $($if_no:tt)* }})?) => {{",
|
|
version
|
|
)?;
|
|
writeln!(macro_file, " $($if_yes)*")?;
|
|
writeln!(macro_file, " }};")?;
|
|
}
|
|
for version in (minor + 1)..(MAX_USED_VERSION + 1) {
|
|
writeln!(
|
|
macro_file,
|
|
" (if >= 1.{} {{ $($if_yes:tt)* }} $(else {{ $($if_no:tt)* }})?) => {{",
|
|
version
|
|
)?;
|
|
writeln!(macro_file, " $($($if_no)*)?")?;
|
|
writeln!(macro_file, " }};")?;
|
|
}
|
|
writeln!(macro_file, " (if >= $unknown:tt $($rest:tt)*) => {{")?;
|
|
writeln!(
|
|
macro_file,
|
|
" compile_error!(concat!(\"unknown Rust version \", stringify!($unknown)));"
|
|
)?;
|
|
writeln!(macro_file, " }};")?;
|
|
writeln!(macro_file, "}}")?;
|
|
writeln!(macro_file, "pub use rust_version;")?;
|
|
macro_file.flush()
|
|
}
|