This README explains how to run script/trim_includes.py, what it does, and how to prepare any C project so the script can accurately detect and trim unused #include directives.
- Scans C files (default: everything under
src/). - Finds the first contiguous block of
#includelines at the top of each file. - Builds a temporary copy, removing one include at a time and compiling; if compilation fails without that header, the include is marked as needed.
- Optionally rewrites the file so only the needed includes remain.
- Safety pass: after trimming, it recompiles; if the reduced set fails, it re-adds removed headers (in original order) until compilation succeeds.
- Check only:
python3 script/trim_includes.py - Check verbose:
python3 script/trim_includes.py --verbose - Apply fixes:
python3 script/trim_includes.py --fix - Single file:
python3 script/trim_includes.py --file src/assemble/config_color.c --fix
Defaults are derived from the top-level Makefile (INCLUDES, CFLAGS).
--src-dir DIR: Root to search for*.c(default:src).--compiler CC: Compiler to use (default:cc).--makefile PATH: Makefile to readINCLUDES/CFLAGSfrom (default:Makefile).--include FLAG: Extra-I…flag; overrides Makefile includes when provided (repeatable).--cflag FLAG: Extra compiler flag; overrides Makefile CFLAGS when provided (repeatable).--file PATH: Limit to one or more files (repeatable). Paths can be relative or absolute.--fix: Rewrite include blocks to keep only needed headers.--verbose: Show compiler commands/stdout/stderr for each probe compile.
Exit code is non-zero if any file fails the baseline compile or if a fix attempt cannot produce a compilable result.
- Ensure compilable units
- Each file should compile standalone with the project’s normal include paths and CFLAGS. If a file requires special flags that differ from the project defaults, pass them via
--include/--cflagor a custom--makefile.
- Expose include paths and flags
- Add
INCLUDES(e.g.,-Iinclude -Isrc -Ithird_party) andCFLAGSin your Makefile as single-line assignments so the script can parse them. Avoid multi-line continuations. - If your build uses macros that are mandatory for headers to parse, add them to
CFLAGS(or pass via--cflag -DMACRO).
- Keep include blocks contiguous
- Place the file’s
#includedirectives in one block at the top, optionally separated by blank lines. The script only inspects the first contiguous include/blank region.
- Keep headers idempotent
- Headers should be guarded (
#ifndef/#define/#endif). Non-idempotent headers can cause spurious compilation failures when probed.
- Handle generated headers
- If some headers are generated, ensure they exist before running the script (run your codegen first or point
--includeto the generated output directory).
- Optional: restrict scope
- For large trees, start with a subset:
--file path/to/foo.c --file path/to/bar.c.
[check] file.c: needed N, removable M: Dry-run summary. Removable items are listed.[fix] file.c: kept N, removed M: File rewritten with the trimmed include block.[error] file.c: failed to compile baseline; skipping: The original file did not compile with the provided flags; fix your flags or the code, then rerun.[error] file.c: trimmed includes fail to compile; keeping original block: The safety pass could not find a compilable reduced set; the file is left untouched.
- Run after a clean build setup so generated headers and submodules are present.
- Use
--verbosewhen investigating why a header is considered needed. - If your project mixes C and C++, do not point
--src-dirat C++ files; the script assumes C compilation. - For non-standard file layouts, specify both
--src-dirand--makefileexplicitly.
Assume a project with sources under source/, headers in include/, and a Makefile with INCLUDES/CFLAGS:
python3 script/trim_includes.py \
--src-dir source \
--makefile Makefile \
--fix
If your project needs extra flags for a specific platform:
python3 script/trim_includes.py \
--src-dir source \
--makefile Makefile \
--cflag -DPLATFORM_LINUX \
--include -Ithird_party/special \
--fix
- Baseline compile fails: ensure the file builds normally with the same compiler/flags; pass required
-I/-Dflags or fix the code. - Wrong includes removed: rerun with
--verboseto see failing probes; if needed, temporarily pin a header by adding a dependency that requires it. - Multi-line Makefile vars: the parser is simple and only handles single-line assignments; flatten your
INCLUDES/CFLAGSor override via CLI.