1// rustc-cfg emitted by the build script: 2// 3// "wrap_proc_macro" 4// Wrap types from libproc_macro rather than polyfilling the whole API. 5// Enabled on rustc 1.29+ as long as procmacro2_semver_exempt is not set, 6// because we can't emulate the unstable API without emulating everything 7// else. Also enabled unconditionally on nightly, in which case the 8// procmacro2_semver_exempt surface area is implemented by using the 9// nightly-only proc_macro API. 10// 11// "hygiene" 12// Enable Span::mixed_site() and non-dummy behavior of Span::resolved_at 13// and Span::located_at. Enabled on Rust 1.45+. 14// 15// "proc_macro_span" 16// Enable non-dummy behavior of Span::start and Span::end methods which 17// requires an unstable compiler feature. Enabled when building with 18// nightly, unless `-Z allow-feature` in RUSTFLAGS disallows unstable 19// features. 20// 21// "super_unstable" 22// Implement the semver exempt API in terms of the nightly-only proc_macro 23// API. Enabled when using procmacro2_semver_exempt on a nightly compiler. 24// 25// "span_locations" 26// Provide methods Span::start and Span::end which give the line/column 27// location of a token. Enabled by procmacro2_semver_exempt or the 28// "span-locations" Cargo cfg. This is behind a cfg because tracking 29// location inside spans is a performance hit. 30// 31// "is_available" 32// Use proc_macro::is_available() to detect if the proc macro API is 33// available or needs to be polyfilled instead of trying to use the proc 34// macro API and catching a panic if it isn't available. Enabled on Rust 35// 1.57+. 36 37use std::env; 38use std::ffi::OsString; 39use std::path::Path; 40use std::process::{self, Command, Stdio}; 41use std::str; 42use std::u32; 43 44fn main() { 45 let rustc = rustc_minor_version().unwrap_or(u32::MAX); 46 47 let docs_rs = env::var_os("DOCS_RS").is_some(); 48 let semver_exempt = cfg!(procmacro2_semver_exempt) || docs_rs; 49 if semver_exempt { 50 // https://github.com/dtolnay/proc-macro2/issues/147 51 println!("cargo:rustc-cfg=procmacro2_semver_exempt"); 52 } 53 54 if semver_exempt || cfg!(feature = "span-locations") { 55 println!("cargo:rustc-cfg=span_locations"); 56 } 57 58 if rustc < 57 { 59 println!("cargo:rustc-cfg=no_is_available"); 60 } 61 62 if rustc < 66 { 63 println!("cargo:rustc-cfg=no_source_text"); 64 } 65 66 if !cfg!(feature = "proc-macro") { 67 println!("cargo:rerun-if-changed=build.rs"); 68 return; 69 } 70 71 println!("cargo:rerun-if-changed=build/probe.rs"); 72 73 let proc_macro_span; 74 let consider_rustc_bootstrap; 75 if compile_probe(false) { 76 // This is a nightly or dev compiler, so it supports unstable features 77 // regardless of RUSTC_BOOTSTRAP. No need to rerun build script if 78 // RUSTC_BOOTSTRAP is changed. 79 proc_macro_span = true; 80 consider_rustc_bootstrap = false; 81 } else if let Some(rustc_bootstrap) = env::var_os("RUSTC_BOOTSTRAP") { 82 if compile_probe(true) { 83 // This is a stable or beta compiler for which the user has set 84 // RUSTC_BOOTSTRAP to turn on unstable features. Rerun build script 85 // if they change it. 86 proc_macro_span = true; 87 consider_rustc_bootstrap = true; 88 } else if rustc_bootstrap == "1" { 89 // This compiler does not support the proc macro Span API in the 90 // form that proc-macro2 expects. No need to pay attention to 91 // RUSTC_BOOTSTRAP. 92 proc_macro_span = false; 93 consider_rustc_bootstrap = false; 94 } else { 95 // This is a stable or beta compiler for which RUSTC_BOOTSTRAP is 96 // set to restrict the use of unstable features by this crate. 97 proc_macro_span = false; 98 consider_rustc_bootstrap = true; 99 } 100 } else { 101 // Without RUSTC_BOOTSTRAP, this compiler does not support the proc 102 // macro Span API in the form that proc-macro2 expects, but try again if 103 // the user turns on unstable features. 104 proc_macro_span = false; 105 consider_rustc_bootstrap = true; 106 } 107 108 if proc_macro_span || !semver_exempt { 109 println!("cargo:rustc-cfg=wrap_proc_macro"); 110 } 111 112 if proc_macro_span { 113 println!("cargo:rustc-cfg=proc_macro_span"); 114 } 115 116 if semver_exempt && proc_macro_span { 117 println!("cargo:rustc-cfg=super_unstable"); 118 } 119 120 if consider_rustc_bootstrap { 121 println!("cargo:rerun-if-env-changed=RUSTC_BOOTSTRAP"); 122 } 123} 124 125fn compile_probe(rustc_bootstrap: bool) -> bool { 126 if env::var_os("RUSTC_STAGE").is_some() { 127 // We are running inside rustc bootstrap. This is a highly non-standard 128 // environment with issues such as: 129 // 130 // https://github.com/rust-lang/cargo/issues/11138 131 // https://github.com/rust-lang/rust/issues/114839 132 // 133 // Let's just not use nightly features here. 134 return false; 135 } 136 137 let rustc = cargo_env_var("RUSTC"); 138 let out_dir = cargo_env_var("OUT_DIR"); 139 let probefile = Path::new("build").join("probe.rs"); 140 141 // Make sure to pick up Cargo rustc configuration. 142 let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER") { 143 let mut cmd = Command::new(wrapper); 144 // The wrapper's first argument is supposed to be the path to rustc. 145 cmd.arg(rustc); 146 cmd 147 } else { 148 Command::new(rustc) 149 }; 150 151 if !rustc_bootstrap { 152 cmd.env_remove("RUSTC_BOOTSTRAP"); 153 } 154 155 cmd.stderr(Stdio::null()) 156 .arg("--edition=2021") 157 .arg("--crate-name=proc_macro2") 158 .arg("--crate-type=lib") 159 .arg("--emit=dep-info,metadata") 160 .arg("--out-dir") 161 .arg(out_dir) 162 .arg(probefile); 163 164 if let Some(target) = env::var_os("TARGET") { 165 cmd.arg("--target").arg(target); 166 } 167 168 // If Cargo wants to set RUSTFLAGS, use that. 169 if let Ok(rustflags) = env::var("CARGO_ENCODED_RUSTFLAGS") { 170 if !rustflags.is_empty() { 171 for arg in rustflags.split('\x1f') { 172 cmd.arg(arg); 173 } 174 } 175 } 176 177 match cmd.status() { 178 Ok(status) => status.success(), 179 Err(_) => false, 180 } 181} 182 183fn rustc_minor_version() -> Option<u32> { 184 let rustc = cargo_env_var("RUSTC"); 185 let output = Command::new(rustc).arg("--version").output().ok()?; 186 let version = str::from_utf8(&output.stdout).ok()?; 187 let mut pieces = version.split('.'); 188 if pieces.next() != Some("rustc 1") { 189 return None; 190 } 191 pieces.next()?.parse().ok() 192} 193 194fn cargo_env_var(key: &str) -> OsString { 195 env::var_os(key).unwrap_or_else(|| { 196 eprintln!( 197 "Environment variable ${} is not set during execution of build script", 198 key, 199 ); 200 process::exit(1); 201 }) 202} 203