-
Notifications
You must be signed in to change notification settings - Fork 13k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Auto merge of #36758 - michaelwoerister:incr-comp-file-headers, r=eddyb
incr.comp.: Let the compiler ignore incompatible incr. comp. cache artifacts Implements #35720. cc @nikomatsakis
- Loading branch information
Showing
7 changed files
with
202 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
//! This module defines a generic file format that allows to check if a given | ||
//! file generated by incremental compilation was generated by a compatible | ||
//! compiler version. This file format is used for the on-disk version of the | ||
//! dependency graph and the exported metadata hashes. | ||
//! | ||
//! In practice "compatible compiler version" means "exactly the same compiler | ||
//! version", since the header encodes the git commit hash of the compiler. | ||
//! Since we can always just ignore the incremental compilation cache and | ||
//! compiler versions don't change frequently for the typical user, being | ||
//! conservative here practically has no downside. | ||
use std::io::{self, Read}; | ||
use std::path::Path; | ||
use std::fs::File; | ||
use std::env; | ||
|
||
use rustc::session::config::nightly_options; | ||
|
||
/// The first few bytes of files generated by incremental compilation | ||
const FILE_MAGIC: &'static [u8] = b"RSIC"; | ||
|
||
/// Change this if the header format changes | ||
const HEADER_FORMAT_VERSION: u16 = 0; | ||
|
||
/// A version string that hopefully is always different for compiler versions | ||
/// with different encodings of incremental compilation artifacts. Contains | ||
/// the git commit hash. | ||
const RUSTC_VERSION: Option<&'static str> = option_env!("CFG_VERSION"); | ||
|
||
pub fn write_file_header<W: io::Write>(stream: &mut W) -> io::Result<()> { | ||
stream.write_all(FILE_MAGIC)?; | ||
stream.write_all(&[(HEADER_FORMAT_VERSION >> 0) as u8, | ||
(HEADER_FORMAT_VERSION >> 8) as u8])?; | ||
|
||
let rustc_version = rustc_version(); | ||
assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); | ||
stream.write_all(&[rustc_version.len() as u8])?; | ||
stream.write_all(rustc_version.as_bytes())?; | ||
|
||
Ok(()) | ||
} | ||
|
||
/// Reads the contents of a file with a file header as defined in this module. | ||
/// | ||
/// - Returns `Ok(Some(data))` if the file existed and was generated by a | ||
/// compatible compiler version. `data` is the entire contents of the file | ||
/// *after* the header. | ||
/// - Returns `Ok(None)` if the file did not exist or was generated by an | ||
/// incompatible version of the compiler. | ||
/// - Returns `Err(..)` if some kind of IO error occurred while reading the | ||
/// file. | ||
pub fn read_file(path: &Path) -> io::Result<Option<Vec<u8>>> { | ||
if !path.exists() { | ||
return Ok(None); | ||
} | ||
|
||
let mut file = File::open(path)?; | ||
|
||
// Check FILE_MAGIC | ||
{ | ||
debug_assert!(FILE_MAGIC.len() == 4); | ||
let mut file_magic = [0u8; 4]; | ||
file.read_exact(&mut file_magic)?; | ||
if file_magic != FILE_MAGIC { | ||
return Ok(None) | ||
} | ||
} | ||
|
||
// Check HEADER_FORMAT_VERSION | ||
{ | ||
debug_assert!(::std::mem::size_of_val(&HEADER_FORMAT_VERSION) == 2); | ||
let mut header_format_version = [0u8; 2]; | ||
file.read_exact(&mut header_format_version)?; | ||
let header_format_version = (header_format_version[0] as u16) | | ||
((header_format_version[1] as u16) << 8); | ||
|
||
if header_format_version != HEADER_FORMAT_VERSION { | ||
return Ok(None) | ||
} | ||
} | ||
|
||
// Check RUSTC_VERSION | ||
{ | ||
let mut rustc_version_str_len = [0u8; 1]; | ||
file.read_exact(&mut rustc_version_str_len)?; | ||
let rustc_version_str_len = rustc_version_str_len[0] as usize; | ||
let mut buffer = Vec::with_capacity(rustc_version_str_len); | ||
buffer.resize(rustc_version_str_len, 0); | ||
file.read_exact(&mut buffer[..])?; | ||
|
||
if &buffer[..] != rustc_version().as_bytes() { | ||
return Ok(None); | ||
} | ||
} | ||
|
||
let mut data = vec![]; | ||
file.read_to_end(&mut data)?; | ||
|
||
Ok(Some(data)) | ||
} | ||
|
||
fn rustc_version() -> String { | ||
if nightly_options::is_nightly_build() { | ||
if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") { | ||
return val.to_string_lossy().into_owned() | ||
} | ||
} | ||
|
||
RUSTC_VERSION.expect("Cannot use rustc without explicit version for \ | ||
incremental compilation") | ||
.to_string() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | ||
// file at the top-level directory of this distribution and at | ||
// http://rust-lang.org/COPYRIGHT. | ||
// | ||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | ||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | ||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | ||
// option. This file may not be copied, modified, or distributed | ||
// except according to those terms. | ||
|
||
// This test case makes sure that the compiler does not try to re-use anything | ||
// from the incremental compilation cache if the cache was produced by a | ||
// different compiler version. This is tested by artificially forcing the | ||
// emission of a different compiler version in the header of rpass1 artifacts, | ||
// and then making sure that the only object file of the test program gets | ||
// re-translated although the program stays unchanged. | ||
|
||
// The `l33t haxx0r` Rust compiler is known to produce incr. comp. artifacts | ||
// that are outrageously incompatible with just about anything, even itself: | ||
//[rpass1] rustc-env:RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER="l33t haxx0r rustc 2.1 LTS" | ||
|
||
// revisions:rpass1 rpass2 | ||
|
||
#![feature(rustc_attrs)] | ||
#![rustc_partition_translated(module="cache_file_headers", cfg="rpass2")] | ||
|
||
fn main() { | ||
// empty | ||
} |