diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index c4a38047b5e3b..1521601691a3a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -391,8 +391,7 @@ fn escape_dep_filename(filename: &str) -> String { // Makefile comments only need escaping newlines and `\`. // The result can be unescaped by anything that can unescape `escape_default` and friends. -fn escape_dep_env(symbol: Symbol) -> String { - let s = symbol.as_str(); +fn escape_dep_env(s: &str) -> String { let mut escaped = String::with_capacity(s.len()); for c in s.chars() { match c { @@ -492,16 +491,22 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P // Emit special comments with information about accessed environment variables. let env_depinfo = sess.psess.env_depinfo.borrow(); + + // We will soon sort, so the initial order does not matter. + #[allow(rustc::potential_query_instability)] + let mut env_depinfo: Vec<_> = env_depinfo + .iter() + .map(|(k, v)| (escape_dep_env(k.as_str()), v.map(|v| escape_dep_env(v.as_str())))) + .chain(tcx.sess.target.is_like_osx.then(|| { + // On Apple targets, we also depend on the deployment target environment variable. + let name = rustc_target::spec::apple_deployment_target_env(&tcx.sess.target.os); + (name.into(), std::env::var(name).ok().map(|var| escape_dep_env(&var))) + })) + .collect(); + env_depinfo.sort_unstable(); if !env_depinfo.is_empty() { - // We will soon sort, so the initial order does not matter. - #[allow(rustc::potential_query_instability)] - let mut envs: Vec<_> = env_depinfo - .iter() - .map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env))) - .collect(); - envs.sort_unstable(); writeln!(file)?; - for (k, v) in envs { + for (k, v) in env_depinfo { write!(file, "# env-dep:{k}")?; if let Some(v) = v { write!(file, "={v}")?; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f3e3b36111c54..0df2a432f1446 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1188,6 +1188,7 @@ impl Default for Options { color: ColorConfig::Auto, logical_env: FxIndexMap::default(), verbose: false, + apple_deployment_target_env: None, } } } @@ -2734,6 +2735,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M color, logical_env, verbose, + apple_deployment_target_env: None, } } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a57dc80b3168d..f03fd12036a4c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -222,6 +222,15 @@ top_level_options!( color: ColorConfig [UNTRACKED], verbose: bool [TRACKED_NO_CRATE_HASH], + + /// The raw value of the `*_DEPLOYMENT_TARGET` environment variable + /// for the selected target OS. + /// + /// The exact environment variable to use depends on the target that + /// the user has chosen, and we do not want to re-compile if an + /// unrelated deployment target environment variable changed, so we + /// defer the initialization of this to `build_session`. + apple_deployment_target_env: Option [TRACKED], } ); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 70430d82ab55b..974fb56aeda03 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -995,7 +995,7 @@ fn default_emitter( #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable pub fn build_session( early_dcx: EarlyDiagCtxt, - sopts: config::Options, + mut sopts: config::Options, io: CompilerIO, bundle: Option>, registry: rustc_errors::registry::Registry, @@ -1099,6 +1099,13 @@ pub fn build_session( let asm_arch = if target.allow_asm { InlineAsmArch::from_str(&target.arch).ok() } else { None }; + // Configure the deployment target for change-tracking, now that target + // details are available. + if target.is_like_osx { + let name = rustc_target::spec::apple_deployment_target_env(&target.os); + sopts.apple_deployment_target_env = std::env::var(name).ok(); + } + let sess = Session { target, host, diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index b1fe49f76caa3..9b7ddd1ca1a01 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -283,6 +283,19 @@ pub fn platform(target: &Target) -> Option { }) } +/// Name of the environment variable used to fetch the deployment target on +/// the given OS. +pub fn deployment_target_env(os: &str) -> &'static str { + match os { + "macos" => "MACOSX_DEPLOYMENT_TARGET", + "ios" => "IPHONEOS_DEPLOYMENT_TARGET", + "watchos" => "WATCHOS_DEPLOYMENT_TARGET", + "tvos" => "TVOS_DEPLOYMENT_TARGET", + "visionos" => "XROS_DEPLOYMENT_TARGET", + _ => unreachable!("tried to get deployment target env var for non-Apple platform"), + } +} + /// Hack for calling `deployment_target` outside of this module. pub fn deployment_target_for_target(target: &Target) -> (u16, u8, u8) { let arch = if target.llvm_target.starts_with("arm64e") { @@ -332,17 +345,13 @@ fn deployment_target(os: &str, arch: Arch, abi: TargetAbi) -> (u16, u8, u8) { _ => os_min, }; - // The environment variable used to fetch the deployment target. - let env_var = match os { - "macos" => "MACOSX_DEPLOYMENT_TARGET", - "ios" => "IPHONEOS_DEPLOYMENT_TARGET", - "watchos" => "WATCHOS_DEPLOYMENT_TARGET", - "tvos" => "TVOS_DEPLOYMENT_TARGET", - "visionos" => "XROS_DEPLOYMENT_TARGET", - _ => unreachable!("tried to get deployment target env var for non-Apple platform"), - }; - - if let Ok(deployment_target) = env::var(env_var) { + // NOTE: We access the deployment target environment variable here, which + // makes the variable an **implicit** input which affects compilation. + // + // We make sure to rebuild when the variable changes, both by busting the + // incremental cache, and by telling Cargo that it is a dependency. + // Search for usages of `deployment_target_env` to see how. + if let Ok(deployment_target) = env::var(deployment_target_env(os)) { match parse_version(&deployment_target) { // It is common that the deployment target is set too low, e.g. on // macOS Aarch64 to also target older x86_64, the user may set a diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 58d47c201f018..341f4cb0d7f44 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -60,6 +60,7 @@ pub mod crt_objects; mod base; pub use base::apple::{ + deployment_target_env as apple_deployment_target_env, deployment_target_for_target as current_apple_deployment_target, platform as current_apple_platform, sdk_version as current_apple_sdk_version, }; diff --git a/tests/run-make/apple-deployment-target/rmake.rs b/tests/run-make/apple-deployment-target/rmake.rs index b2d1af65177ef..3db7cbf2c139b 100644 --- a/tests/run-make/apple-deployment-target/rmake.rs +++ b/tests/run-make/apple-deployment-target/rmake.rs @@ -137,11 +137,6 @@ fn main() { rustc }; - // FIXME(madsmtm): Incremental cache is not yet busted - // https://github.com/rust-lang/rust/issues/118204 - let higher_example_version = example_version; - let default_version = example_version; - rustc().env(env_var, example_version).run(); minos("foo.o", example_version);