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.
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.
14 use std
::io
::{self, Read}
;
17 use rustc_serialize
::opaque
::{FileEncodeResult, FileEncoder}
;
19 /// The first few bytes of files generated by incremental compilation.
20 const FILE_MAGIC
: &[u8] = b
"RSIC";
22 /// Change this if the header format changes.
23 const HEADER_FORMAT_VERSION
: u16 = 0;
25 /// A version string that hopefully is always different for compiler versions
26 /// with different encodings of incremental compilation artifacts. Contains
27 /// the Git commit hash.
28 const RUSTC_VERSION
: Option
<&str> = option_env
!("CFG_VERSION");
30 pub fn write_file_header(stream
: &mut FileEncoder
, nightly_build
: bool
) -> FileEncodeResult
{
31 stream
.emit_raw_bytes(FILE_MAGIC
)?
;
32 stream
.emit_raw_bytes(&[
33 (HEADER_FORMAT_VERSION
>> 0) as u8,
34 (HEADER_FORMAT_VERSION
>> 8) as u8,
37 let rustc_version
= rustc_version(nightly_build
);
38 assert_eq
!(rustc_version
.len(), (rustc_version
.len() as u8) as usize);
39 stream
.emit_raw_bytes(&[rustc_version
.len() as u8])?
;
40 stream
.emit_raw_bytes(rustc_version
.as_bytes())
43 /// Reads the contents of a file with a file header as defined in this module.
45 /// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a
46 /// compatible compiler version. `data` is the entire contents of the file
47 /// and `pos` points to the first byte after the header.
48 /// - Returns `Ok(None)` if the file did not exist or was generated by an
49 /// incompatible version of the compiler.
50 /// - Returns `Err(..)` if some kind of IO error occurred while reading the
53 report_incremental_info
: bool
,
56 ) -> io
::Result
<Option
<(Vec
<u8>, usize)>> {
57 let data
= match fs
::read(path
) {
59 Err(err
) if err
.kind() == io
::ErrorKind
::NotFound
=> return Ok(None
),
60 Err(err
) => return Err(err
),
63 let mut file
= io
::Cursor
::new(data
);
67 debug_assert
!(FILE_MAGIC
.len() == 4);
68 let mut file_magic
= [0u8; 4];
69 file
.read_exact(&mut file_magic
)?
;
70 if file_magic
!= FILE_MAGIC
{
71 report_format_mismatch(report_incremental_info
, path
, "Wrong FILE_MAGIC");
76 // Check HEADER_FORMAT_VERSION
78 debug_assert
!(::std
::mem
::size_of_val(&HEADER_FORMAT_VERSION
) == 2);
79 let mut header_format_version
= [0u8; 2];
80 file
.read_exact(&mut header_format_version
)?
;
81 let header_format_version
=
82 (header_format_version
[0] as u16) | ((header_format_version
[1] as u16) << 8);
84 if header_format_version
!= HEADER_FORMAT_VERSION
{
85 report_format_mismatch(report_incremental_info
, path
, "Wrong HEADER_FORMAT_VERSION");
90 // Check RUSTC_VERSION
92 let mut rustc_version_str_len
= [0u8; 1];
93 file
.read_exact(&mut rustc_version_str_len
)?
;
94 let rustc_version_str_len
= rustc_version_str_len
[0] as usize;
95 let mut buffer
= vec
![0; rustc_version_str_len
];
96 file
.read_exact(&mut buffer
)?
;
98 if buffer
!= rustc_version(nightly_build
).as_bytes() {
99 report_format_mismatch(report_incremental_info
, path
, "Different compiler version");
104 let post_header_start_pos
= file
.position() as usize;
105 Ok(Some((file
.into_inner(), post_header_start_pos
)))
108 fn report_format_mismatch(report_incremental_info
: bool
, file
: &Path
, message
: &str) {
109 debug
!("read_file: {}", message
);
111 if report_incremental_info
{
113 "[incremental] ignoring cache artifact `{}`: {}",
114 file
.file_name().unwrap().to_string_lossy(),
120 fn rustc_version(nightly_build
: bool
) -> String
{
122 if let Some(val
) = env
::var_os("RUSTC_FORCE_INCR_COMP_ARTIFACT_HEADER") {
123 return val
.to_string_lossy().into_owned();
129 "Cannot use rustc without explicit version for \
130 incremental compilation",