in src/compiler/c.rs [682:794]
fn process_preprocessed_file(
input_file: &Path,
cwd: &Path,
bytes: &mut [u8],
included_files: &mut HashMap<PathBuf, String>,
config: PreprocessorCacheModeConfig,
time_of_compilation: std::time::SystemTime,
fs_impl: impl PreprocessorFSAbstraction,
) -> Result<bool> {
let mut start = 0;
let mut hash_start = 0;
let total_len = bytes.len();
let mut digest = Digest::new();
let mut normalized_include_paths: HashMap<Vec<u8>, Option<Vec<u8>>> = HashMap::new();
// There must be at least 7 characters (# 1 "x") left to potentially find an
// include file path.
while start < total_len.saturating_sub(7) {
let mut slice = &bytes[start..];
// Check if we look at a line containing the file name of an included file.
// At least the following formats exist (where N is a positive integer):
//
// GCC:
//
// # N "file"
// # N "file" N
// #pragma GCC pch_preprocess "file"
//
// HP's compiler:
//
// #line N "file"
//
// AIX's compiler:
//
// #line N "file"
// #line N
//
// Note that there may be other lines starting with '#' left after
// preprocessing as well, for instance "# pragma".
if slice[0] == b'#'
// GCC:
&& ((slice[1] == b' ' && slice[2] >= b'0' && slice[2] <= b'9')
// GCC precompiled header:
|| slice[1..].starts_with(PRAGMA_GCC_PCH_PREPROCESS)
// HP/AIX:
|| (&slice[1..5] == b"line "))
&& (start == 0 || bytes[start - 1] == b'\n')
{
match process_preprocessor_line(
input_file,
cwd,
included_files,
config,
time_of_compilation,
bytes,
start,
hash_start,
&mut digest,
total_len,
&mut normalized_include_paths,
&fs_impl,
)? {
ControlFlow::Continue((s, h)) => {
start = s;
hash_start = h;
}
ControlFlow::Break((s, h, continue_preprocessor_cache_mode)) => {
if !continue_preprocessor_cache_mode {
return Ok(false);
}
start = s;
hash_start = h;
continue;
}
};
} else if slice
.strip_prefix(INCBIN_DIRECTIVE)
.filter(|slice| {
slice.starts_with(b"\"") || slice.starts_with(b" \"") || slice.starts_with(b" \\\"")
})
.is_some()
{
// An assembler .inc bin (without the space) statement, which could be
// part of inline assembly, refers to an external file. If the file
// changes, the hash should change as well, but finding out what file to
// hash is too hard for sccache, so just bail out.
debug!("Found potential unsupported .inc bin directive in source code");
return Ok(false);
} else if slice.starts_with(b"___________") && (start == 0 || bytes[start - 1] == b'\n') {
// Unfortunately the distcc-pump wrapper outputs standard output lines:
// __________Using distcc-pump from /usr/bin
// __________Using # distcc servers in pump mode
// __________Shutting down distcc-pump include server
digest.update(&bytes[hash_start..start]);
while start < total_len && slice[0] != b'\n' {
start += 1;
if start < total_len {
slice = &bytes[start..];
}
}
slice = &bytes[start..];
if slice[0] == b'\n' {
start += 1;
}
hash_start = start;
continue;
} else {
start += 1;
}
}
digest.update(&bytes[hash_start..]);
Ok(true)
}