in src/compiler/c.rs [1006:1118]
fn remember_include_file(
mut path: &[u8],
input_file: &Path,
cwd: &Path,
included_files: &mut HashMap<PathBuf, String>,
digest: &mut Digest,
system: bool,
config: PreprocessorCacheModeConfig,
time_of_compilation: std::time::SystemTime,
fs_impl: &impl PreprocessorFSAbstraction,
) -> Result<bool> {
// TODO if precompiled header.
if path.len() >= 2 && path[0] == b'<' && path[path.len() - 1] == b'>' {
// Typically <built-in> or <command-line>.
digest.update(path);
return Ok(true);
}
if system && config.skip_system_headers {
// Don't remember this system header, only hash its path.
digest.update(path);
return Ok(true);
}
let original_path = path;
// Canonicalize path for comparison; Clang uses ./header.h.
#[cfg(windows)]
{
if path.starts_with(br".\") || path.starts_with(b"./") {
path = &path[2..];
}
}
#[cfg(not(windows))]
{
if path.starts_with(b"./") {
path = &path[2..];
}
}
let mut path = decode_path(path).context("failed to decode path")?;
if path.is_relative() {
path = cwd.join(path);
}
if path != cwd || config.hash_working_directory {
digest.update(original_path);
}
if included_files.contains_key(&path) {
// Already known include file
return Ok(true);
}
if path == input_file {
// Don't remember the input file.
return Ok(true);
}
let meta = match fs_impl.metadata(&path) {
Ok(meta) => meta,
Err(e) => {
debug!("Failed to stat include file {}: {}", path.display(), e);
return Ok(false);
}
};
if meta.is_dir {
// Ignore directory, typically $PWD.
return Ok(true);
}
if !meta.is_file {
// Device, pipe, socket or other strange creature.
debug!("Non-regular include file {}", path.display());
return Ok(false);
}
// TODO add an option to ignore some header files?
if include_is_too_new(&path, &meta, time_of_compilation) {
return Ok(false);
}
// Let's hash the include file content.
let file = match fs_impl.open(&path) {
Ok(file) => file,
Err(e) => {
debug!("Failed to open header file {}: {}", path.display(), e);
return Ok(false);
}
};
let (file_digest, finder) = if config.ignore_time_macros {
match Digest::reader_sync(file) {
Ok(file_digest) => (file_digest, TimeMacroFinder::new()),
Err(e) => {
debug!("Failed to read header file {}: {}", path.display(), e);
return Ok(false);
}
}
} else {
match Digest::reader_sync_time_macros(file) {
Ok((file_digest, finder)) => (file_digest, finder),
Err(e) => {
debug!("Failed to read header file {}: {}", path.display(), e);
return Ok(false);
}
}
};
if finder.found_time() {
debug!("Found __TIME__ in header file {}", path.display());
return Ok(false);
}
included_files.insert(path, file_digest);
Ok(true)
}