Skip to content

Commit 298e403

Browse files
authored
fix(build-rs): Implicitly report rerun-if-env-changed for input (#14911)
### What does this PR try to resolve? As we abstract away the env variables, users can't do a good job of reporting these, so we'll do it ourselves. ### How should we test and review this PR? This isn't the shortest path to this solution because I had originally designed this like more like [`build_env`](https://docs.rs/build-env/latest/build_env/struct.BuildEnv.html) but in a way to allow users to choose what policies they want (rather than baking in their HOST/TARGET scheme). I decided to not support a custom `env` yet to make this more incremental and to see what feedback we get but I left the implementation in a way that would make it easy to support it. I made `is_present` part of `Env` because I was unsure if callers of the API would want to handle that differently for `rerun-if-env-changed` or other parts. ### Additional information CC @CAD97
2 parents 27a4f98 + 6c021e0 commit 298e403

File tree

1 file changed

+85
-32
lines changed

1 file changed

+85
-32
lines changed

crates/build-rs/src/input.rs

Lines changed: 85 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,66 @@
66
//!
77
//! Reference: <https://doc.rust-lang.org/stable/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts>
88
9-
use std::env::var_os;
109
use std::path::PathBuf;
1110

1211
use crate::ident::{is_ascii_ident, is_crate_name, is_feature_name};
12+
use crate::output::rerun_if_env_changed;
13+
14+
/// [`ProcessEnv`] wrapper that implicit calls [`rerun_if_env_changed`]
15+
const ENV: RerunIfEnvChanged<ProcessEnv> = RerunIfEnvChanged::new();
16+
17+
/// Abstraction over environment variables
18+
trait Env {
19+
/// Fetches the environment variable `key`, returning `None` if the variable isn’t set or if
20+
/// there is another error.
21+
///
22+
/// It may return `None` if the environment variable’s name contains the equal sign character
23+
/// (`=`) or the NUL character.
24+
///
25+
/// Note that this function will not check if the environment variable is valid Unicode.
26+
fn get(&self, key: &str) -> Option<std::ffi::OsString>;
27+
28+
/// Checks the environment variable `key` is present
29+
///
30+
/// It may not be considered present if the environment variable’s name contains the equal sign character
31+
/// (`=`) or the NUL character.
32+
fn is_present(&self, key: &str) -> bool;
33+
}
34+
35+
/// Fetches environment variables from the current process
36+
struct ProcessEnv;
37+
38+
impl Env for ProcessEnv {
39+
fn get(&self, key: &str) -> Option<std::ffi::OsString> {
40+
std::env::var_os(key)
41+
}
42+
43+
fn is_present(&self, key: &str) -> bool {
44+
self.get(key).is_some()
45+
}
46+
}
47+
48+
/// [`Env`] wrapper that implicitly calls [`rerun_if_env_changed`]
49+
struct RerunIfEnvChanged<E: Env>(E);
50+
51+
impl RerunIfEnvChanged<ProcessEnv> {
52+
const fn new() -> Self {
53+
Self(ProcessEnv)
54+
}
55+
}
56+
57+
impl<E: Env> Env for RerunIfEnvChanged<E> {
58+
#[track_caller]
59+
fn get(&self, key: &str) -> Option<std::ffi::OsString> {
60+
rerun_if_env_changed(key);
61+
self.0.get(key)
62+
}
63+
64+
#[track_caller]
65+
fn is_present(&self, key: &str) -> bool {
66+
self.get(key).is_some()
67+
}
68+
}
1369

1470
/// Path to the `cargo` binary performing the build.
1571
#[track_caller]
@@ -30,7 +86,7 @@ pub fn cargo_manifest_dir() -> PathBuf {
3086
/// The path to the manifest of your package.
3187
#[track_caller]
3288
pub fn cargo_manifest_path() -> PathBuf {
33-
var_os("CARGO_MANIFEST_PATH")
89+
ENV.get("CARGO_MANIFEST_PATH")
3490
.map(to_path)
3591
.unwrap_or_else(|| {
3692
let mut path = cargo_manifest_dir();
@@ -42,7 +98,7 @@ pub fn cargo_manifest_path() -> PathBuf {
4298
/// The manifest `links` value.
4399
#[track_caller]
44100
pub fn cargo_manifest_links() -> Option<String> {
45-
var_os("CARGO_MANIFEST_LINKS").map(to_string)
101+
ENV.get("CARGO_MANIFEST_LINKS").map(to_string)
46102
}
47103

48104
/// Contains parameters needed for Cargo’s [jobserver] implementation to parallelize
@@ -57,7 +113,7 @@ pub fn cargo_manifest_links() -> Option<String> {
57113
/// [jobserver]: https://www.gnu.org/software/make/manual/html_node/Job-Slots.html
58114
#[track_caller]
59115
pub fn cargo_makeflags() -> Option<String> {
60-
var_os("CARGO_MAKEFLAGS").map(to_string)
116+
ENV.get("CARGO_MAKEFLAGS").map(to_string)
61117
}
62118

63119
/// For each activated feature of the package being built, this will be `true`.
@@ -68,7 +124,7 @@ pub fn cargo_feature(name: &str) -> bool {
68124
}
69125
let name = name.to_uppercase().replace('-', "_");
70126
let key = format!("CARGO_FEATURE_{name}");
71-
is_present(&key)
127+
ENV.is_present(&key)
72128
}
73129

74130
/// For each [configuration option] of the package being built, this will contain
@@ -82,7 +138,7 @@ pub fn cargo_feature(name: &str) -> bool {
82138
#[track_caller]
83139
pub fn cargo_cfg(cfg: &str) -> Option<Vec<String>> {
84140
let var = cargo_cfg_var(cfg);
85-
var_os(&var).map(|v| to_strings(v, ','))
141+
ENV.get(&var).map(|v| to_strings(v, ','))
86142
}
87143

88144
#[track_caller]
@@ -112,7 +168,7 @@ mod cfg {
112168
#[cfg(any())]
113169
#[track_caller]
114170
pub fn cargo_cfg_clippy() -> bool {
115-
is_present("CARGO_CFG_CLIPPY")
171+
ENV.is_present("CARGO_CFG_CLIPPY")
116172
}
117173

118174
/// If we are compiling with debug assertions enabled.
@@ -123,25 +179,25 @@ mod cfg {
123179
#[cfg(any())]
124180
#[track_caller]
125181
pub fn cargo_cfg_debug_assertions() -> bool {
126-
is_present("CARGO_CFG_DEBUG_ASSERTIONS")
182+
ENV.is_present("CARGO_CFG_DEBUG_ASSERTIONS")
127183
}
128184

129185
#[cfg(any())]
130186
#[track_caller]
131187
pub fn cargo_cfg_doc() -> bool {
132-
is_present("CARGO_CFG_DOC")
188+
ENV.is_present("CARGO_CFG_DOC")
133189
}
134190

135191
#[cfg(any())]
136192
#[track_caller]
137193
pub fn cargo_cfg_docsrs() -> bool {
138-
is_present("CARGO_CFG_DOCSRS")
194+
ENV.is_present("CARGO_CFG_DOCSRS")
139195
}
140196

141197
#[cfg(any())]
142198
#[track_caller]
143199
pub fn cargo_cfg_doctest() -> bool {
144-
is_present("CARGO_CFG_DOCTEST")
200+
ENV.is_present("CARGO_CFG_DOCTEST")
145201
}
146202

147203
/// The level of detail provided by derived [`Debug`] implementations.
@@ -155,15 +211,15 @@ mod cfg {
155211
#[cfg(any())]
156212
#[track_caller]
157213
pub fn cargo_cfg_miri() -> bool {
158-
is_present("CARGO_CFG_MIRI")
214+
ENV.is_present("CARGO_CFG_MIRI")
159215
}
160216

161217
/// If we are compiling with overflow checks enabled.
162218
#[doc = unstable!(cfg_overflow_checks, 111466)]
163219
#[cfg(feature = "unstable")]
164220
#[track_caller]
165221
pub fn cargo_cfg_overflow_checks() -> bool {
166-
is_present("CARGO_CFG_OVERFLOW_CHECKS")
222+
ENV.is_present("CARGO_CFG_OVERFLOW_CHECKS")
167223
}
168224

169225
/// The [panic strategy](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#panic).
@@ -175,7 +231,7 @@ mod cfg {
175231
/// If the crate is being compiled as a procedural macro.
176232
#[track_caller]
177233
pub fn cargo_cfg_proc_macro() -> bool {
178-
is_present("CARGO_CFG_PROC_MACRO")
234+
ENV.is_present("CARGO_CFG_PROC_MACRO")
179235
}
180236

181237
/// The target relocation model.
@@ -189,31 +245,31 @@ mod cfg {
189245
#[cfg(any())]
190246
#[track_caller]
191247
pub fn cargo_cfg_rustfmt() -> bool {
192-
is_present("CARGO_CFG_RUSTFMT")
248+
ENV.is_present("CARGO_CFG_RUSTFMT")
193249
}
194250

195251
/// Sanitizers enabled for the crate being compiled.
196252
#[doc = unstable!(cfg_sanitize, 39699)]
197253
#[cfg(feature = "unstable")]
198254
#[track_caller]
199255
pub fn cargo_cfg_sanitize() -> Option<Vec<String>> {
200-
var_os("CARGO_CFG_SANITIZE").map(|v| to_strings(v, ','))
256+
ENV.get("CARGO_CFG_SANITIZE").map(|v| to_strings(v, ','))
201257
}
202258

203259
/// If CFI sanitization is generalizing pointers.
204260
#[doc = unstable!(cfg_sanitizer_cfi, 89653)]
205261
#[cfg(feature = "unstable")]
206262
#[track_caller]
207263
pub fn cargo_cfg_sanitizer_cfi_generalize_pointers() -> bool {
208-
is_present("CARGO_CFG_SANITIZER_CFI_GENERALIZE_POINTERS")
264+
ENV.is_present("CARGO_CFG_SANITIZER_CFI_GENERALIZE_POINTERS")
209265
}
210266

211267
/// If CFI sanitization is normalizing integers.
212268
#[doc = unstable!(cfg_sanitizer_cfi, 89653)]
213269
#[cfg(feature = "unstable")]
214270
#[track_caller]
215271
pub fn cargo_cfg_sanitizer_cfi_normalize_integers() -> bool {
216-
is_present("CARGO_CFG_SANITIZER_CFI_NORMALIZE_INTEGERS")
272+
ENV.is_present("CARGO_CFG_SANITIZER_CFI_NORMALIZE_INTEGERS")
217273
}
218274

219275
/// Disambiguation of the [target ABI](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_abi)
@@ -309,7 +365,7 @@ mod cfg {
309365
#[cfg(feature = "unstable")]
310366
#[track_caller]
311367
pub fn cargo_cfg_target_thread_local() -> bool {
312-
is_present("CARGO_CFG_TARGET_THREAD_LOCAL")
368+
ENV.is_present("CARGO_CFG_TARGET_THREAD_LOCAL")
313369
}
314370

315371
/// The [target vendor](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#target_vendor).
@@ -321,27 +377,27 @@ mod cfg {
321377
#[cfg(any())]
322378
#[track_caller]
323379
pub fn cargo_cfg_test() -> bool {
324-
is_present("CARGO_CFG_TEST")
380+
ENV.is_present("CARGO_CFG_TEST")
325381
}
326382

327383
/// If we are compiling with UB checks enabled.
328384
#[doc = unstable!(cfg_ub_checks, 123499)]
329385
#[cfg(feature = "unstable")]
330386
#[track_caller]
331387
pub fn cargo_cfg_ub_checks() -> bool {
332-
is_present("CARGO_CFG_UB_CHECKS")
388+
ENV.is_present("CARGO_CFG_UB_CHECKS")
333389
}
334390

335391
/// Set on [unix-like platforms](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#unix-and-windows).
336392
#[track_caller]
337393
pub fn cargo_cfg_unix() -> bool {
338-
is_present("CARGO_CFG_UNIX")
394+
ENV.is_present("CARGO_CFG_UNIX")
339395
}
340396

341397
/// Set on [windows-like platforms](https://doc.rust-lang.org/stable/reference/conditional-compilation.html#unix-and-windows).
342398
#[track_caller]
343399
pub fn cargo_cfg_windows() -> bool {
344-
is_present("CARGO_CFG_WINDOWS")
400+
ENV.is_present("CARGO_CFG_WINDOWS")
345401
}
346402
}
347403

@@ -428,7 +484,7 @@ pub fn dep_metadata(name: &str, key: &str) -> Option<String> {
428484
let name = name.to_uppercase().replace('-', "_");
429485
let key = key.to_uppercase().replace('-', "_");
430486
let key = format!("DEP_{name}_{key}");
431-
var_os(&key).map(to_string)
487+
ENV.get(&key).map(to_string)
432488
}
433489

434490
/// The compiler that Cargo has resolved to use.
@@ -448,7 +504,7 @@ pub fn rustdoc() -> PathBuf {
448504
/// [`build.rustc-wrapper`]: https://doc.rust-lang.org/stable/cargo/reference/config.html#buildrustc-wrapper
449505
#[track_caller]
450506
pub fn rustc_wrapper() -> Option<PathBuf> {
451-
var_os("RUSTC_WRAPPER").map(to_path)
507+
ENV.get("RUSTC_WRAPPER").map(to_path)
452508
}
453509

454510
/// The rustc wrapper, if any, that Cargo is using for workspace members. See
@@ -457,15 +513,15 @@ pub fn rustc_wrapper() -> Option<PathBuf> {
457513
/// [`build.rustc-workspace-wrapper`]: https://doc.rust-lang.org/stable/cargo/reference/config.html#buildrustc-workspace-wrapper
458514
#[track_caller]
459515
pub fn rustc_workspace_wrapper() -> Option<PathBuf> {
460-
var_os("RUSTC_WORKSPACE_WRAPPER").map(to_path)
516+
ENV.get("RUSTC_WORKSPACE_WRAPPER").map(to_path)
461517
}
462518

463519
/// The linker that Cargo has resolved to use for the current target, if specified.
464520
///
465521
/// [`target.*.linker`]: https://doc.rust-lang.org/stable/cargo/reference/config.html#targettriplelinker
466522
#[track_caller]
467523
pub fn rustc_linker() -> Option<PathBuf> {
468-
var_os("RUSTC_LINKER").map(to_path)
524+
ENV.get("RUSTC_LINKER").map(to_path)
469525
}
470526

471527
/// Extra flags that Cargo invokes rustc with. See [`build.rustflags`].
@@ -561,13 +617,10 @@ pub fn cargo_pkg_readme() -> Option<PathBuf> {
561617
to_opt(var_or_panic("CARGO_PKG_README")).map(to_path)
562618
}
563619

564-
fn is_present(key: &str) -> bool {
565-
var_os(key).is_some()
566-
}
567-
568620
#[track_caller]
569621
fn var_or_panic(key: &str) -> std::ffi::OsString {
570-
var_os(key).unwrap_or_else(|| panic!("cargo environment variable `{key}` is missing"))
622+
ENV.get(key)
623+
.unwrap_or_else(|| panic!("cargo environment variable `{key}` is missing"))
571624
}
572625

573626
fn to_path(value: std::ffi::OsString) -> PathBuf {

0 commit comments

Comments
 (0)