]>
Commit | Line | Data |
---|---|---|
9e0c209e SL |
1 | //! This module defines a generic file format that allows to check if a given |
2 | //! file generated by incremental compilation was generated by a compatible | |
3 | //! compiler version. This file format is used for the on-disk version of the | |
4 | //! dependency graph and the exported metadata hashes. | |
5 | //! | |
6 | //! In practice "compatible compiler version" means "exactly the same compiler | |
7 | //! version", since the header encodes the git commit hash of the compiler. | |
8 | //! Since we can always just ignore the incremental compilation cache and | |
9 | //! compiler versions don't change frequently for the typical user, being | |
10 | //! conservative here practically has no downside. | |
11 | ||
dfeec247 XL |
12 | use std::env; |
13 | use std::fs; | |
9e0c209e SL |
14 | use std::io::{self, Read}; |
15 | use std::path::Path; | |
9e0c209e | 16 | |
5869c6ff | 17 | use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; |
cdc7bbd5 | 18 | use rustc_serialize::Encoder; |
9e0c209e | 19 | |
9fa01778 | 20 | /// The first few bytes of files generated by incremental compilation. |
0731742a | 21 | const FILE_MAGIC: &[u8] = b"RSIC"; |
9e0c209e | 22 | |
9fa01778 | 23 | /// Change this if the header format changes. |
9e0c209e SL |
24 | const HEADER_FORMAT_VERSION: u16 = 0; |
25 | ||
26 | /// A version string that hopefully is always different for compiler versions | |
27 | /// with different encodings of incremental compilation artifacts. Contains | |
9fa01778 | 28 | /// the Git commit hash. |
0731742a | 29 | const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); |
9e0c209e | 30 | |
5869c6ff XL |
31 | pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult { |
32 | stream.emit_raw_bytes(FILE_MAGIC)?; | |
33 | stream.emit_raw_bytes(&[ | |
34 | (HEADER_FORMAT_VERSION >> 0) as u8, | |
35 | (HEADER_FORMAT_VERSION >> 8) as u8, | |
36 | ])?; | |
9e0c209e | 37 | |
fc512014 | 38 | let rustc_version = rustc_version(nightly_build); |
9e0c209e | 39 | assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); |
5869c6ff XL |
40 | stream.emit_raw_bytes(&[rustc_version.len() as u8])?; |
41 | stream.emit_raw_bytes(rustc_version.as_bytes()) | |
9e0c209e SL |
42 | } |
43 | ||
44 | /// Reads the contents of a file with a file header as defined in this module. | |
45 | /// | |
abe05a73 | 46 | /// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a |
9e0c209e | 47 | /// compatible compiler version. `data` is the entire contents of the file |
abe05a73 | 48 | /// and `pos` points to the first byte after the header. |
9e0c209e SL |
49 | /// - Returns `Ok(None)` if the file did not exist or was generated by an |
50 | /// incompatible version of the compiler. | |
51 | /// - Returns `Err(..)` if some kind of IO error occurred while reading the | |
52 | /// file. | |
dfeec247 XL |
53 | pub fn read_file( |
54 | report_incremental_info: bool, | |
55 | path: &Path, | |
fc512014 | 56 | nightly_build: bool, |
dfeec247 | 57 | ) -> io::Result<Option<(Vec<u8>, usize)>> { |
5869c6ff XL |
58 | let data = match fs::read(path) { |
59 | Ok(data) => data, | |
60 | Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None), | |
61 | Err(err) => return Err(err), | |
62 | }; | |
abe05a73 XL |
63 | |
64 | let mut file = io::Cursor::new(data); | |
9e0c209e SL |
65 | |
66 | // Check FILE_MAGIC | |
67 | { | |
68 | debug_assert!(FILE_MAGIC.len() == 4); | |
69 | let mut file_magic = [0u8; 4]; | |
70 | file.read_exact(&mut file_magic)?; | |
71 | if file_magic != FILE_MAGIC { | |
ff7c6d11 | 72 | report_format_mismatch(report_incremental_info, path, "Wrong FILE_MAGIC"); |
dfeec247 | 73 | return Ok(None); |
9e0c209e SL |
74 | } |
75 | } | |
76 | ||
77 | // Check HEADER_FORMAT_VERSION | |
78 | { | |
79 | debug_assert!(::std::mem::size_of_val(&HEADER_FORMAT_VERSION) == 2); | |
80 | let mut header_format_version = [0u8; 2]; | |
81 | file.read_exact(&mut header_format_version)?; | |
dfeec247 XL |
82 | let header_format_version = |
83 | (header_format_version[0] as u16) | ((header_format_version[1] as u16) << 8); | |
9e0c209e SL |
84 | |
85 | if header_format_version != HEADER_FORMAT_VERSION { | |
ff7c6d11 | 86 | report_format_mismatch(report_incremental_info, path, "Wrong HEADER_FORMAT_VERSION"); |
dfeec247 | 87 | return Ok(None); |
9e0c209e SL |
88 | } |
89 | } | |
90 | ||
91 | // Check RUSTC_VERSION | |
92 | { | |
93 | let mut rustc_version_str_len = [0u8; 1]; | |
94 | file.read_exact(&mut rustc_version_str_len)?; | |
95 | let rustc_version_str_len = rustc_version_str_len[0] as usize; | |
74b04a01 | 96 | let mut buffer = vec![0; rustc_version_str_len]; |
cc61c64b | 97 | file.read_exact(&mut buffer)?; |
9e0c209e | 98 | |
fc512014 | 99 | if buffer != rustc_version(nightly_build).as_bytes() { |
ff7c6d11 | 100 | report_format_mismatch(report_incremental_info, path, "Different compiler version"); |
9e0c209e SL |
101 | return Ok(None); |
102 | } | |
103 | } | |
104 | ||
abe05a73 XL |
105 | let post_header_start_pos = file.position() as usize; |
106 | Ok(Some((file.into_inner(), post_header_start_pos))) | |
9e0c209e SL |
107 | } |
108 | ||
ff7c6d11 | 109 | fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) { |
476ff2be SL |
110 | debug!("read_file: {}", message); |
111 | ||
ff7c6d11 | 112 | if report_incremental_info { |
6a06907d | 113 | eprintln!( |
dfeec247 XL |
114 | "[incremental] ignoring cache artifact `{}`: {}", |
115 | file.file_name().unwrap().to_string_lossy(), | |
116 | message | |
117 | ); | |
476ff2be SL |
118 | } |
119 | } | |
120 | ||
fc512014 XL |
121 | fn rustc_version(nightly_build: bool) -> String { |
122 | if nightly_build { | |
9e0c209e | 123 | if let Some(val) = env::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") { |
dfeec247 | 124 | return val.to_string_lossy().into_owned(); |
9e0c209e SL |
125 | } |
126 | } | |
127 | ||
dfeec247 XL |
128 | RUSTC_VERSION |
129 | .expect( | |
130 | "Cannot use rustc without explicit version for \ | |
131 | incremental compilation", | |
132 | ) | |
133 | .to_string() | |
9e0c209e | 134 | } |