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;
109use std:: path:: PathBuf ;
1110
1211use 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]
3288pub 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]
44100pub 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]
59115pub 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]
83139pub 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]
450506pub 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]
459515pub 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]
467523pub 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]
569621fn 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
573626fn to_path ( value : std:: ffi:: OsString ) -> PathBuf {
0 commit comments