fn remember_include_file()

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)
}