@@ -527,3 +527,98 @@ fn target_linker(bcx: &BuildContext<'_, '_>, kind: CompileKind) -> CargoResult<O
527527 }
528528 Ok ( matching_linker. map ( |( _k, linker) | linker. val . clone ( ) . resolve_program ( bcx. gctx ) ) )
529529}
530+
531+ /// This tracks environment variables Cargo sets to rustc when building a crate.
532+ ///
533+ /// This only inclues variables with statically known keys.
534+ /// For environment variable keys that vary like `CARG_BIN_EXE_<name>` or
535+ /// `-Zbindeps` related env vars, we compare only their prefixes to determine
536+ /// if they are internal.
537+ /// See [`is_env_set_by_cargo`] and
538+ /// <https://doc.rust-lang.org/nightly/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>.
539+ const ENV_VARS_SET_FOR_CRATES : [ & str ; 23 ] = [
540+ crate :: CARGO_ENV ,
541+ "CARGO_MANIFEST_DIR" ,
542+ "CARGO_MANIFEST_PATH" ,
543+ "CARGO_PKG_VERSION" ,
544+ "CARGO_PKG_VERSION_MAJOR" ,
545+ "CARGO_PKG_VERSION_MINOR" ,
546+ "CARGO_PKG_VERSION_PATCH" ,
547+ "CARGO_PKG_VERSION_PRE" ,
548+ "CARGO_PKG_AUTHORS" ,
549+ "CARGO_PKG_NAME" ,
550+ "CARGO_PKG_DESCRIPTION" ,
551+ "CARGO_PKG_HOMEPAGE" ,
552+ "CARGO_PKG_REPOSITORY" ,
553+ "CARGO_PKG_LICENSE" ,
554+ "CARGO_PKG_LICENSE_FILE" ,
555+ "CARGO_PKG_RUST_VERSION" ,
556+ "CARGO_PKG_README" ,
557+ "CARGO_CRATE_NAME" ,
558+ "CARGO_BIN_NAME" ,
559+ "OUT_DIR" ,
560+ "CARGO_PRIMARY_PACKAGE" ,
561+ "CARGO_TARGET_TMPDIR" ,
562+ paths:: dylib_path_envvar ( ) ,
563+ ] ;
564+ /// Asserts if the given env vars are controlled by Cargo.
565+ ///
566+ /// This is only for reminding Cargo developer to keep newly added environment
567+ /// variables in sync with [`ENV_VARS_SET_FOR_CRATES`].
568+ #[ cfg( debug_assertions) ]
569+ pub ( crate ) fn assert_only_envs_set_by_cargo < ' a > (
570+ keys : impl Iterator < Item = impl AsRef < str > > ,
571+ env_config : & HashMap < String , OsString > ,
572+ ) {
573+ for key in keys {
574+ let key = key. as_ref ( ) ;
575+ // When running Cargo's test suite,
576+ // we're fine if it is from the `[env]` table
577+ if env_config. contains_key ( key) {
578+ continue ;
579+ }
580+ assert ! (
581+ is_env_set_by_cargo( key) ,
582+ "`{key}` is not tracked as an environment variable set by Cargo\n \
583+ Add it to `ENV_VARS_SET_FOR_CRATES` if you intend to introduce a new one"
584+ ) ;
585+ }
586+ }
587+
588+ /// True if the given env var is controlled or set by Cargo.
589+ /// See [`ENV_VARS_SET_FOR_CRATES`].
590+ pub ( crate ) fn is_env_set_by_cargo ( key : & str ) -> bool {
591+ ENV_VARS_SET_FOR_CRATES . contains ( & key)
592+ || key. starts_with ( "CARGO_BIN_EXE_" )
593+ || key. starts_with ( "__CARGO" ) // internal/test-only envs
594+ || key == "RUSTC_BOOTSTRAP" // for -Zbuild-std
595+ || is_artifact_dep_env_vars ( key)
596+ }
597+
598+ /// Whether an env var is set because of `-Zbindeps`.
599+ fn is_artifact_dep_env_vars ( key : & str ) -> bool {
600+ let Some ( key) = key. strip_prefix ( "CARGO_" ) else {
601+ return false ;
602+ } ;
603+ let Some ( key) = key
604+ . strip_prefix ( "BIN_" )
605+ . or_else ( || key. strip_prefix ( "CDYLIB_" ) )
606+ . or_else ( || key. strip_prefix ( "STATICLIB_" ) )
607+ else {
608+ return false ;
609+ } ;
610+ key. starts_with ( "FILE_" ) || key. starts_with ( "DIR_" )
611+ }
612+
613+ #[ cfg( test) ]
614+ mod tests {
615+ use std:: collections:: HashSet ;
616+
617+ use super :: ENV_VARS_SET_FOR_CRATES ;
618+
619+ #[ test]
620+ fn ensure_env_vars_set_for_crates_unique ( ) {
621+ let set: HashSet < & str > = HashSet :: from_iter ( ENV_VARS_SET_FOR_CRATES ) ;
622+ assert_eq ! ( ENV_VARS_SET_FOR_CRATES . len( ) , set. len( ) ) ;
623+ }
624+ }
0 commit comments