]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_incremental/src/persist/file_format.rs
New upstream version 1.56.0+dfsg1
[rustc.git] / compiler / rustc_incremental / src / persist / file_format.rs
CommitLineData
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
12use std::env;
13use std::fs;
9e0c209e
SL
14use std::io::{self, Read};
15use std::path::Path;
9e0c209e 16
5869c6ff 17use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
cdc7bbd5 18use rustc_serialize::Encoder;
9e0c209e 19
9fa01778 20/// The first few bytes of files generated by incremental compilation.
0731742a 21const FILE_MAGIC: &[u8] = b"RSIC";
9e0c209e 22
9fa01778 23/// Change this if the header format changes.
9e0c209e
SL
24const 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 29const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
9e0c209e 30
5869c6ff
XL
31pub 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
53pub 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 109fn 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
121fn 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}