From 072b7db56161ee4c7a4411d8398c90512c153e16 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 18 Jun 2022 10:19:24 +0000 Subject: [PATCH 1/2] Make debug_triple depend on target json file content rather than file path This ensures that changes to target json files will force a recompilation. And more importantly that moving the files doesn't force a recompilation. --- compiler/rustc_target/src/spec/mod.rs | 50 +++++++++++++++------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 422af66787579..6670f3845c8bd 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -2183,7 +2183,7 @@ impl Target { TargetTriple::TargetTriple(ref target_triple) => { load_builtin(target_triple).expect("built-in target") } - TargetTriple::TargetPath(..) => { + TargetTriple::TargetJson { .. } => { panic!("built-in targets doens't support target-paths") } } @@ -2248,11 +2248,9 @@ impl Target { Err(format!("Could not find specification for target {:?}", target_triple)) } - TargetTriple::TargetPath(ref target_path) => { - if target_path.is_file() { - return load_file(&target_path); - } - Err(format!("Target path {:?} is not a valid file", target_path)) + TargetTriple::TargetJson { triple: _, ref contents } => { + let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; + Target::from_json(obj) } } } @@ -2424,7 +2422,7 @@ impl ToJson for Target { #[derive(PartialEq, Clone, Debug, Hash, Encodable, Decodable)] pub enum TargetTriple { TargetTriple(String), - TargetPath(PathBuf), + TargetJson { triple: String, contents: String }, } impl TargetTriple { @@ -2436,7 +2434,19 @@ impl TargetTriple { /// Creates a target triple from the passed target path. pub fn from_path(path: &Path) -> Result { let canonicalized_path = path.canonicalize()?; - Ok(TargetTriple::TargetPath(canonicalized_path)) + let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Target path {:?} is not a valid file: {}", canonicalized_path, err), + ) + })?; + let triple = canonicalized_path + .file_stem() + .expect("target path must not be empty") + .to_str() + .expect("target path must be valid unicode") + .to_owned(); + Ok(TargetTriple::TargetJson { triple, contents }) } /// Returns a string triple for this target. @@ -2444,12 +2454,8 @@ impl TargetTriple { /// If this target is a path, the file name (without extension) is returned. pub fn triple(&self) -> &str { match *self { - TargetTriple::TargetTriple(ref triple) => triple, - TargetTriple::TargetPath(ref path) => path - .file_stem() - .expect("target path must not be empty") - .to_str() - .expect("target path must be valid unicode"), + TargetTriple::TargetTriple(ref triple) + | TargetTriple::TargetJson { ref triple, contents: _ } => triple, } } @@ -2461,14 +2467,14 @@ impl TargetTriple { use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; - let triple = self.triple(); - if let TargetTriple::TargetPath(ref path) = *self { - let mut hasher = DefaultHasher::new(); - path.hash(&mut hasher); - let hash = hasher.finish(); - format!("{}-{}", triple, hash) - } else { - triple.into() + match self { + TargetTriple::TargetTriple(triple) => triple.to_owned(), + TargetTriple::TargetJson { triple, contents: content } => { + let mut hasher = DefaultHasher::new(); + content.hash(&mut hasher); + let hash = hasher.finish(); + format!("{}-{}", triple, hash) + } } } } From b4b536d34d8d2371a4be95a2b294bbf0088807b7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 18 Jun 2022 10:48:46 +0000 Subject: [PATCH 2/2] Preserve the path of the target spec json file for usage by rustdoc --- compiler/rustc_target/src/spec/mod.rs | 84 ++++++++++++++++++++++++--- src/librustdoc/doctest.rs | 4 +- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 6670f3845c8bd..fd0c3f36e7299 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -39,11 +39,13 @@ use crate::json::{Json, ToJson}; use crate::spec::abi::{lookup as lookup_abi, Abi}; use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_span::symbol::{sym, Symbol}; use serde_json::Value; use std::borrow::Cow; use std::collections::BTreeMap; use std::convert::TryFrom; +use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; @@ -2248,7 +2250,7 @@ impl Target { Err(format!("Could not find specification for target {:?}", target_triple)) } - TargetTriple::TargetJson { triple: _, ref contents } => { + TargetTriple::TargetJson { ref contents, .. } => { let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?; Target::from_json(obj) } @@ -2419,10 +2421,77 @@ impl ToJson for Target { } /// Either a target triple string or a path to a JSON file. -#[derive(PartialEq, Clone, Debug, Hash, Encodable, Decodable)] +#[derive(Clone, Debug)] pub enum TargetTriple { TargetTriple(String), - TargetJson { triple: String, contents: String }, + TargetJson { + /// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to + /// inconsistencies as it is discarded during serialization. + path_for_rustdoc: PathBuf, + triple: String, + contents: String, + }, +} + +// Use a manual implementation to ignore the path field +impl PartialEq for TargetTriple { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0, + ( + Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents }, + Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents }, + ) => l_triple == r_triple && l_contents == r_contents, + _ => false, + } + } +} + +// Use a manual implementation to ignore the path field +impl Hash for TargetTriple { + fn hash(&self, state: &mut H) -> () { + match self { + TargetTriple::TargetTriple(triple) => { + 0u8.hash(state); + triple.hash(state) + } + TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => { + 1u8.hash(state); + triple.hash(state); + contents.hash(state) + } + } + } +} + +// Use a manual implementation to prevent encoding the target json file path in the crate metadata +impl Encodable for TargetTriple { + fn encode(&self, s: &mut S) { + match self { + TargetTriple::TargetTriple(triple) => s.emit_enum_variant(0, |s| s.emit_str(triple)), + TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => s + .emit_enum_variant(1, |s| { + s.emit_str(triple); + s.emit_str(contents) + }), + } + } +} + +impl Decodable for TargetTriple { + fn decode(d: &mut D) -> Self { + match d.read_usize() { + 0 => TargetTriple::TargetTriple(d.read_str().to_owned()), + 1 => TargetTriple::TargetJson { + path_for_rustdoc: PathBuf::new(), + triple: d.read_str().to_owned(), + contents: d.read_str().to_owned(), + }, + _ => { + panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2"); + } + } + } } impl TargetTriple { @@ -2437,7 +2506,7 @@ impl TargetTriple { let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| { io::Error::new( io::ErrorKind::InvalidInput, - format!("Target path {:?} is not a valid file: {}", canonicalized_path, err), + format!("target path {:?} is not a valid file: {}", canonicalized_path, err), ) })?; let triple = canonicalized_path @@ -2446,7 +2515,7 @@ impl TargetTriple { .to_str() .expect("target path must be valid unicode") .to_owned(); - Ok(TargetTriple::TargetJson { triple, contents }) + Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents }) } /// Returns a string triple for this target. @@ -2455,7 +2524,7 @@ impl TargetTriple { pub fn triple(&self) -> &str { match *self { TargetTriple::TargetTriple(ref triple) - | TargetTriple::TargetJson { ref triple, contents: _ } => triple, + | TargetTriple::TargetJson { ref triple, .. } => triple, } } @@ -2465,11 +2534,10 @@ impl TargetTriple { /// by `triple()`. pub fn debug_triple(&self) -> String { use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; match self { TargetTriple::TargetTriple(triple) => triple.to_owned(), - TargetTriple::TargetJson { triple, contents: content } => { + TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => { let mut hasher = DefaultHasher::new(); content.hash(&mut hasher); let hash = hasher.finish(); diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 86c58cd79dce0..ab72f4a3f502c 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -365,8 +365,8 @@ fn run_test( } compiler.arg("--target").arg(match target { TargetTriple::TargetTriple(s) => s, - TargetTriple::TargetPath(path) => { - path.to_str().expect("target path must be valid unicode").to_string() + TargetTriple::TargetJson { path_for_rustdoc, .. } => { + path_for_rustdoc.to_str().expect("target path must be valid unicode").to_string() } }); if let ErrorOutputType::HumanReadable(kind) = rustdoc_options.error_format {