use std::env; use std::ffi::OsString; use std::io::Write; use std::path::PathBuf; use std::process::{Child, Command, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; const RT_CHECK_ENV: &str = "DUNGEON_CELL_RUNTIME_CHECKS"; const NO_CONST_TYPE_NAME: &str = "DUNGEON_CELL_NO_CONST_TYPE_NAME"; fn main() { // Sanity check that probe works. assert!(probe("")); let const_type_name_override = std::env::var_os(NO_CONST_TYPE_NAME).is_some(); let const_assert_override = env::var_os(RT_CHECK_ENV).is_some(); if !const_type_name_override && probe("pub const PROBE: () = ((), core::any::type_name::<()>()).0;") { emit("has_const_type_name"); } else if !const_type_name_override && probe( r#" #![feature(const_type_name)] pub const PROBE: () = ((), core::any::type_name::<()>()).0; "#, ) { emit("has_feature_const_type_name"); emit("has_const_type_name"); } if !const_assert_override { emit("use_const_assert"); } rerun_env(RT_CHECK_ENV); rerun_env(NO_CONST_TYPE_NAME); rerun_path(file!()); } // ---------- // Following is modified from https://github.com/cuviper/autocfg/blob/master/src/lib.rs // Original code is licensed under Apache or MIT. pub fn rerun_path(path: &str) { println!("cargo:rerun-if-changed={}", path); } pub fn rerun_env(var: &str) { println!("cargo:rerun-if-env-changed={}", var); } fn emit(cfg: &str) { println!("cargo:rustc-cfg={}", cfg); } fn rustc_path() -> PathBuf { env::var_os("RUSTC") .unwrap_or_else(|| "rustc".into()) .into() } fn out_dir() -> PathBuf { env::var_os("OUT_DIR").unwrap().into() } fn target() -> Option { env::var_os("TARGET") } fn rustflags() -> Vec { let flags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap_or("".to_owned()); if flags.is_empty() { Vec::new() } else { flags.split('\x1f').map(str::to_string).collect() } } static ID: AtomicUsize = AtomicUsize::new(0); fn probe>(code: T) -> bool { let mut child = new_rustc_child(); let mut stdin = child.stdin.take().expect("rustc stdin"); stdin .write_all(b"#![no_std]\n#![allow(warnings)]\n") .unwrap(); stdin.write_all(code.as_ref()).unwrap(); drop(stdin); let status = child.wait().unwrap(); status.success() } fn new_rustc_child() -> Child { let id = ID.fetch_add(1, Ordering::Relaxed); let mut command = Command::new(rustc_path()); command .arg("--crate-name") .arg(format!("probe{}", id)) .arg("--crate-type=lib") .arg("--out-dir") .arg(out_dir()) .arg("--emit=llvm-ir"); if let Some(target) = target() { command.arg("--target").arg(target); } command.args(rustflags()); command.arg("-").stdin(Stdio::piped()); command.stdout(Stdio::null()).stderr(Stdio::null()); command.spawn().unwrap() }