Delete a PCH file if its input files have changed since it was built. Uses the ``.d.cache`` and ``.input_hash`` files saved by previous builds to detect when a header dependency has been modified. If the hash doesn't match, the PCH and hash file are removed so Ninja is forced to rebuil
(pch_file: Path)
| 205 | |
| 206 | |
| 207 | def invalidate_stale_pch(pch_file: Path) -> None: |
| 208 | """Delete a PCH file if its input files have changed since it was built. |
| 209 | |
| 210 | Uses the ``.d.cache`` and ``.input_hash`` files saved by previous builds |
| 211 | to detect when a header dependency has been modified. If the hash doesn't |
| 212 | match, the PCH and hash file are removed so Ninja is forced to rebuild. |
| 213 | |
| 214 | This works around a Ninja limitation on Windows where backslash paths in |
| 215 | depfiles can cause Ninja to miss dependency changes. |
| 216 | """ |
| 217 | if not pch_file.exists(): |
| 218 | return |
| 219 | |
| 220 | saved_depfile = pch_file.with_name(pch_file.name.replace(".pch", ".d.cache")) |
| 221 | hash_file = Path(str(pch_file) + ".input_hash") |
| 222 | if not saved_depfile.exists() or not hash_file.exists(): |
| 223 | # Missing tracking files means we can't verify the PCH is fresh. |
| 224 | # Delete it to force a safe rebuild rather than risking a stale-PCH |
| 225 | # compiler error that would fail the entire build. |
| 226 | print( |
| 227 | f"PCH tracking files missing — removing {pch_file.name} to force rebuild", |
| 228 | file=sys.stderr, |
| 229 | ) |
| 230 | pch_file.unlink(missing_ok=True) |
| 231 | hash_file.unlink(missing_ok=True) |
| 232 | return |
| 233 | |
| 234 | try: |
| 235 | input_files = parse_depfile_inputs(saved_depfile) |
| 236 | if not input_files: |
| 237 | return |
| 238 | current_hash = hash_input_files(input_files) |
| 239 | stored_hash = hash_file.read_text(encoding="utf-8").strip() |
| 240 | if current_hash != stored_hash: |
| 241 | print( |
| 242 | f"PCH inputs changed — removing stale {pch_file.name} to force rebuild", |
| 243 | file=sys.stderr, |
| 244 | ) |
| 245 | pch_file.unlink(missing_ok=True) |
| 246 | hash_file.unlink(missing_ok=True) |
| 247 | except KeyboardInterrupt as ki: |
| 248 | handle_keyboard_interrupt(ki) |
| 249 | raise |
| 250 | except Exception as e: |
| 251 | print(f"WARNING: PCH staleness check failed: {e}", file=sys.stderr) |
| 252 | |
| 253 | |
| 254 | def main() -> int: |
no test coverage detected