CCACHE(1)
โจ NAME โจ
okay bestie, welcome to the ccache(1) page โ yes, manual name ccache, section 1, weโre in the right place ๐
ccache โ a fast C/C++ compiler cache. literally iconic behavior.
๐ธ SYNOPSIS ๐ธ
ccache [ccache options]
ccache [KEY=VALUE ...] compiler [compiler options]
compiler [compiler options]
so there are three forms, and they are giving very different energy:
- the first form takes the options listed in
COMMAND LINE OPTIONSbelow ๐ - the second form runs the compiler, and you can optionally pass configuration options as
KEY=VALUEarguments - the third form is when
ccacheis masquerading as the compiler, as described inRUN MODES
๐ DESCRIPTION ๐
ccache is a compiler cache that speeds up recompilation by storing the results of previous compilations and reusing them when the same compilation is performed again. no cap, it just remembers stuff so you donโt have to wait around again ๐ญโจ
ccache is designed to produce exactly the same compiler output as a normal compilation. the only difference you should notice is faster build times. any known exceptions to this behavior are documented in the CAVEATS section. if you find a case where ccache produces different output than expected, please report it to us ๐ซถ
๐ฆ RUN MODES ๐ฆ
there are exactly two ways to use ccache to cache compilations:
- Prefix method: add
ccachebefore your compilation command. this is the simplest approach when you want to tryccacheor use it for specific projects. example:
ccache gcc -c example.c
- Masquerade method: make
ccacheappear as the compiler by creating a symbolic link toccachewith the compilerโs name. this is useful when you want to useccachefor all compilations. to set upccacheto masquerade asgccandg++:
cp ccache /usr/local/bin/
ln -s ccache /usr/local/bin/gcc
ln -s ccache /usr/local/bin/g++
on systems that donโt support symbolic links, you can copy ccache instead:
cp ccache /usr/local/bin/gcc
cp ccache /usr/local/bin/g++
this works as long as the directory containing the symbolic links or ccache copies appears before the real compiler directory (typically /usr/bin) in your PATH.
โ ๏ธ Warning the masquerade method works well but may conflict with other tools that use the same technique. see USING CCACHE WITH OTHER COMPILER WRAPPERS for more information.
๐ COMMAND LINE OPTIONS ๐
Okay so bestie, listen โ these command line options are only for when you're calling ccache directly, like actually typing "ccache" yourself. When ccache is out here masquerading as a compiler (you know, the whole thing from the last section), you just use your normal compiler options and go read your compiler's docs, k? โจ
๐ Common options ๐
-c,--cleanupโ Cleans up the cache by yeeting out not-recently-used cached files until you're under the specified file number and cache size limits. It also recalculates the cache file count and size totals, slay. Ngl you normally don't need to run this manually โ ccache keeps the cache below the limits at runtime and keeps the stats updated on every compilation. Forcing a cleanup is mostly useful if you've messed with the cache contents yourself or you think the cache size stats are lying to you. ๐-C,--clearโ Nukes the entire cache, removing all cached files, but keeps the configuration file. Like, all of it. Gone. โจ--config-pathPATH โ Lets the command line options operate on configuration file PATH instead of the default one. Using this is literally the same effect as temporarily setting (overriding) the environment variableCCACHE_CONFIGPATH. ๐-d,--dirPATH โ Lets the command line options operate on cache directory PATH instead of the default. Like, say you wanna show stats for a cache directory at/shared/ccache, you'd runccache -d /shared/ccache -s. Same effect as temporarily setting the environment variableCCACHE_DIR. ๐ซถ--dry-runโ Does not perform any write operations. Just vibes, no changes. โจ--evict-namespaceNAMESPACE โ Removes files created in the given namespace from the cache. Bye bestie ๐--evict-older-thanAGE โ Removes files used less recently than AGE from the cache. AGE should be an unsigned integer with ad(days) ors(seconds) suffix. If you combine it with--evict-namespace, it only removes files within that namespace. ๐ง-h,--helpโ Prints a summary of command line options. The classic. ๐-FNUM,--max-filesNUM โ Sets the maximum number of files allowed in the cache to NUM. Use0for no limit. The value gets stored in a configuration file in the cache directory and applies to all future compilations. ๐-MSIZE,--max-sizeSIZE โ Sets the maximum size of the files stored in the cache. SIZE should be a number followed by an optional suffix:kB,MB,GB,TB(decimal),KiB,MiB,GiBorTiB(binary). Default suffix isGiB. Use0for no limit. The value is stored in a configuration file in the cache directory and applies to all future compilations. ๐-XLEVEL,--recompressLEVEL โ Recompresses the cache to level LEVEL using the Zstandard algorithm. The level can be an integer, with the same semantics as thecompression_levelconfiguration option, or the special valueuncompressedfor no compression. See CACHE COMPRESSION for more info (iykyk). Heads up: this can potentially take a long time since all files in the cache need to be visited ๐ญ. Only files currently compressed with a different level than LEVEL get recompressed, so that's something.-oKEY=VALUE,--set-configKEY=VALUE โ Sets configuration option KEY to VALUE in the configuration file. See CONFIGURATION for more. โญ-x,--show-compressionโ Prints cache compression statistics. See CACHE COMPRESSION for more. Also potentially takes a long time since all files in the cache need to be visited ๐.-p,--show-configโ Prints current configuration options and where they originate from (environment variable, configuration file or compile-time default) in human-readable format. Detective mode ๐--show-log-statsโ Prints statistics counters from the stats log in human-readable format. Seestats_log. Use-v/--verboseonce or twice for more details. ๐ธ-s,--show-statsโ Prints a summary of configuration and statistics counters in human-readable format. Use-v/--verboseonce or twice for more details. See Cache statistics for more info. ๐--stop-storage-helpersโ Storage helpers normally stop after a period of client inactivity, but this option stops any running helpers immediately. Like ripping off the band-aid ๐ฉน--threadsTHREADS โ Uses up to THREADS threads for threaded operations. Default is one thread per CPU. Multi-core girlie behavior ๐-v,--verboseโ Increases verbosity. You can give this option multiple times. Say it with your chest ๐ข-V,--versionโ Prints version and copyright information. ๐-z,--zero-statsโ Zeros the cache statistics (but not the configuration options). Fresh start energy โจ
๐ฆ Options for remote file-based storage ๐ฆ
--trim-dirPATH โ Removes not-recently-used files from directory PATH until it's at most the size specified by--trim-max-size.
โ ๏ธ Warning โ ๏ธ Do not use this option to trim the local cache, bestie, I'm serious ๐ญ. To trim the local cache directory to a certain size, use CCACHE_MAXSIZE=SIZE ccache -c.
--trim-max-sizeSIZE โ Specifies the maximum size for--trim-dir. SIZE should be a number followed by an optional suffix:kB,MB,GB,TB(decimal),KiB,MiB,GiBorTiB(binary). The default suffix isGiB. Use0for no limit. ๐ฅ--trim-methodMETHOD โ Specifies the method to trim a directory with--trim-dir. Possible values are:atimeโ LRU (least recently used) using the file access timestamp. This is the default. โฐmtimeโ LRU (least recently used) using the file modification timestamp. ๐
--trim-recompressLEVEL โ Recompresses to level LEVEL using the Zstandard algorithm when using--trim-dir. The level can be an integer, with the same semantics as thecompression_levelconfiguration option, or the special valueuncompressedfor no compression. See CACHE COMPRESSION for more. This can potentially take a long time since all files in the cache need to be visited ๐ญ. Only files currently compressed with a different level than LEVEL get recompressed, ok?
๐ง Options for scripting or debugging ๐ง
--checksum-filePATH โ Prints the checksum (128 bit XXH3) of the file at PATH (-for standard input). ๐--extract-resultPATH โ Extracts data stored in the result file at PATH (-for standard input). The data gets written toccache-result.*files in the current working directory. This option is only useful when debugging ccache and its behavior. ๐--formatFORMAT โ Specifies format for--print-log-statsand--print-stats. Possible values are:tabโ Tab separated. This is the default. ๐jsonโ JSON formatted. ๐งพ
-kKEY,--get-configKEY โ Prints the value of configuration option KEY. See CONFIGURATION for more. ๐--hash-filePATH โ Prints the hash (160 bit BLAKE3) of the file at PATH (-for standard input). This is only useful when debugging ccache and its behavior. ๐--inspectPATH โ Prints the content of a result or manifest file at PATH (-for standard input) to standard output in human-readable format. File content embedded in a result file will however not be printed โ use--extract-resultto extract the file content. This option is only useful when debugging ccache and its behavior. ๐--print-log-statsโ Prints statistics counters from the stats log in machine-parsable (tab-separated or JSON) format. Seestats_logand--format. ๐ค--print-statsโ Prints statistics counter IDs and corresponding values in machine-parsable (tab-separated or JSON) format. See--format. ๐ค--print-versionโ Prints version and does nothing else. Periodt. โจ
๐ Extra options ๐
When run as a compiler, ccache usually just takes the same command line options as the compiler you're using. The only exception to this is the option --ccache-skip. That option tells ccache to avoid interpreting the next option in any way and to pass it along to the compiler as-is. ๐
๐ Note --ccache-skip currently only tells ccache not to interpret the next option as a special compiler option โ the option will still be included in the direct mode hash.
The reason this matters, bestie, is that ccache genuinely needs to parse the command line and figure out what's an input filename and what's a compiler option, because it needs the input filename to determine the name of the resulting object file (among other things). The heuristic ccache uses when parsing the command line is that any argument that exists as a file gets treated as an input file name. By using --ccache-skip you can force an option to not be treated as an input file name and instead be passed along to the compiler as a command line option. ๐ซถ
Another case where --ccache-skip comes in clutch is if ccache interprets an option specially but shouldn't, since the option has another meaning for your compiler than what ccache thinks. ๐ญ
See also ignore_options. ๐
๐ CONFIGURATION ๐
You can customize ccache's behavior using configuration files and environment variables. Configuration options are processed in this order of priority (highest first), no cap:
- Command line settings in KEY=VALUE form. Example:
ccache debug=true compiler_check="%compiler% --version" gcc -c example.c
- Environment variables starting with
CCACHE_. - A directory-specific configuration file.
- The cache-specific configuration file.
- The system-wide configuration file
<sysconfdir>/ccache.conf(typically/etc/ccache.confor/usr/local/etc/ccache.conf). - Compile-time defaults.
Exception: If the environment variable CCACHE_CONFIGPATH is set, it specifies the only configuration file that will be read (environment variables and command line settings still apply). ๐จ
๐ธ Cache-specific configuration file ๐ธ
The location of the cache-specific configuration file is determined like this on non-Windows systems:
- If
CCACHE_CONFIGPATHis set, use that path. - Otherwise, if the environment variable
CCACHE_DIRis set then use$CCACHE_DIR/ccache.conf. - Otherwise, if
cache_diris set in the system configuration file then use<cache_dir>/ccache.conf. - Otherwise, if there's a legacy
$HOME/.ccachedirectory then use$HOME/.ccache/ccache.conf. - Otherwise, if
XDG_CONFIG_HOMEis set then use$XDG_CONFIG_HOME/ccache/ccache.conf. - Otherwise, use
$HOME/Library/Preferences/ccache/ccache.conf(macOS) or$HOME/.config/ccache/ccache.conf(other systems).
On Windows, this is the method used to find the configuration file:
- If
CCACHE_CONFIGPATHis set, use that path. - Otherwise, if the environment variable
CCACHE_DIRis set then use%CCACHE_DIR%/ccache.conf. - Otherwise, if
cache_diris set in the system configuration file then use<cache_dir>\ccache.conf. The system-wide configuration on Windows is%ALLUSERSPROFILE%\ccache\ccache.confby default. TheALLUSERSPROFILEenvironment variable is usuallyC:\ProgramData. ๐ช - Otherwise, if there is a legacy
%USERPROFILE%\.ccachedirectory then use%USERPROFILE%\.ccache\ccache.conf. - Otherwise, use
%LOCALAPPDATA%\ccache\ccache.confif it exists. - Otherwise, use
%APPDATA%\ccache\ccache.conf.
See also the cache_dir configuration option for how the cache directory location is determined. ๐
๐ Directory-specific configuration file ๐
ccache searches for a ccache.conf file (separate from the cache-specific configuration file described above) in the current working directory or any parent directory. The found file must be owned by the effective user and must not be world-writable; otherwise ccache will abort with an error. The search stops when reaching:
- a directory listed in a "ceiling directory" (by default the userโs home directory)
- a directory that contains a "ceiling marker" (by default
.git) - a directory owned by another user
- a file system boundary (mount point)
By default, the file cannot set "unsafe options", i.e. those that affect which commands to execute, which files to write (except cache entries) and which remote storage to use. It is possible to allow unsafe options by adding an entry to safe_dirs. ๐
๐ง Configuration value syntax ๐ง
All configuration values support expansion of environment variables. The syntax is similar to POSIX shell syntax: $VAR or ${VAR}. Both variants will expand to the value of the environment variable VAR.
Two consecutive dollar signs ($$) will expand to a single dollar sign ($). ๐ธ
โจ Configuration file syntax โจ
Configuration files are in a simple โkey = valueโ format, one option per line. Lines starting with a hash sign are comments. Blank lines are ignored, as is whitespace surrounding keys and values. Example:
# Set maximum cache size to 10 GB:
max_size = 10GB
๐ธ Multi-line values ๐ธ
Values can span multiple lines using indentation-based continuation. Lines that start with whitespace (spaces or tabs) are treated as continuation lines and are joined to the previous value with a single space. Comments and blank lines within a multi-line value are skipped. For example:
ignore_options =
-Wall
-Wextra
# This is a comment within the value
-pedantic
# This ends the multi-line value
compiler = gcc
This is equivalent to:
ignore_options = -Wall -Wextra -pedantic
compiler = gcc
Multi-line values are particularly useful for options that accept multiple items. ๐งบ
๐ Boolean values ๐
Some configuration options are boolean values (i.e. truth values). In a configuration file, such values must be set to the string true or false. For the corresponding environment variables, the semantics are a bit different:
- A set environment variable means โtrueโ (even if set to the empty string).
- The following case-insensitive negative values are considered an error (instead of surprising the user):
0,false,disableandno. - An unset environment variable means โfalseโ.
Each boolean environment variable also has a negated form starting with CCACHE_NO. For example, CCACHE_COMPRESS can be set to force compression and CCACHE_NOCOMPRESS can be set to force no compression. โ
โ
๐งต Path lists ๐งต
Options that define a list of paths have their entries separated by ; on Windows and : on other systems.
๐ Configuration options ๐
Below is a list of available configuration options. The corresponding environment variable name is indicated in parentheses after each configuration option key.
absolute_paths_in_stderr (CCACHE_ABSSTDERR)
This option specifies whether ccache should rewrite relative paths in the compilerโs textual output (standard error and standard output) to absolute paths. This can be useful if you use base_dir with a build system (e.g. CMake with the "Unix Makefiles" generator) that executes the compiler in a different working directory, which makes relative paths in compiler errors or warnings incorrect. The default is false. ๐ ๏ธ
base_dir (CCACHE_BASEDIR)
This option specifies a list of absolute paths. When set, ccache converts absolute paths to relative paths before sending them to the compiler (or including them in the input hash), but only for paths that start with one of the specified base directories. "Relative" here means "relative to the current working directory". ๐
This enables cache sharing between compilations in different directories, even when the project uses absolute paths. See COMPILING IN DIFFERENT DIRECTORIES_ for more details. When empty (the default), no path rewriting occurs.
Avoid using / as the base directory as this will also rewrite system header paths, which is usually counterproductive. ๐ซ
Example scenario: Alice works in /home/alice/project1/build and compiles like this:
ccache gcc -I/usr/include/example -I/home/alice/project2/include -c /home/alice/project1/src/example.c
Here is what ccache will actually execute for different base_dir settings:
# Current working directory: /home/alice/project1/build
# With "base_dir = /":
gcc -I../../../../usr/include/example -I../../project2/include -c ../src/example.c
# With "base_dir = /home" or "base_dir = /home/alice":
gcc -I/usr/include/example -I../../project2/include -c ../src/example.c
# With "base_dir = /home/alice/project1" or "base_dir = /home/alice/project1/src":
gcc -I/usr/include/example -I/home/alice/project2/include -c ../src/example.c
If Bob stores the same projects in /home/bob/stuff and both users set base_dir to /home or /home/$USER, they will share cache hits because the rewritten command lines will be identical:
# Current working directory: /home/bob/stuff/project1/build
# With "base_dir = /home" or "base_dir = /home/bob":
gcc -I/usr/include/example -I../../project2/include -c ../src/example.c
Without base_dir there will be a cache miss since the absolute paths will differ. With base_dir set to / there will be a cache miss since the relative path to /usr/include/example will be different. With base_dir set to /home/bob/stuff/project1 there will a cache miss since the path to project2 will be a different absolute path. ๐ญ
Warning Rewriting absolute paths to relative is kind of a brittle hack. It works OK in many cases, but there might be cases where things break. One known issue is that absolute paths are not reproduced in dependency files, which can mess up dependency detection in tools like Make and Ninja. If possible, use relative paths in the first place instead of using base_dir. ๐
cache_dir (CCACHE_DIR)
This option specifies where ccache will keep its cached compiler outputs. ๐
On non-Windows systems, the default is $HOME/.ccache if such a directory exists, otherwise $XDG_CACHE_HOME/ccache if XDG_CACHE_HOME is set, otherwise $HOME/Library/Caches/ccache (macOS) or $HOME/.cache/ccache (other systems).
On Windows, the default is %USERPROFILE%\.ccache if such a directory exists, otherwise %LOCALAPPDATA%\ccache.
Warning Previous ccache versions defaulted to storing the cache in%APPDATA%\ccacheon Windows. This can result in large network file transfers of the cache in domain environments and similar problems. Please check this directory for cache directories and either delete them or the whole directory, or move them to the%LOCALAPPDATA%\ccachedirectory. ๐
See also Cache-specific configuration file.
ceiling_dirs (CCACHE_CEILING_DIRS)
This option specifies absolute directories where ccache will stop searching for a directory-specific configuration file. You might want to set this if accessing files in parent directories is too slow, e.g. on network file systems. The default is to stop looking when reaching the userโs home directory. ๐
ceiling_markers (CCACHE_CEILING_MARKERS)
This option specifies one or more file or directory names (separated by ; on Windows, : on other systems). When searching for a directory-specific configuration file, ccache will stop searching parent directories when it reaches a directory containing any of the specified names. The default is .git. ๐งญ
compiler (CCACHE_COMPILER or (deprecated) CCACHE_CC)
This option can be used to force the name of the compiler to use. If set to the empty string (which is the default), ccache works it out from the command line. ๐งโ๐ป
compiler_check (CCACHE_COMPILERCHECK)
By default, ccache includes the modification time (โmtimeโ) and size of the compiler in the hash to ensure that results retrieved from the cache are accurate. If compiler plugins are used, these plugins will also be added to the hash. This option can be used to select another strategy. Possible values are:
contentโ Hash the content of the compiler binary. This makes ccache very slightly slower compared tomtime, but makes it cope better with compiler upgrades during a build bootstrapping process.mtimeโ Hash the compilerโsmtimeand size, which is fast. This is the default.noneโ Donโt hash anything. This may be good for situations where you can safely use the cached results even though the compilerโsmtimeor size has changed (e.g. if the compiler is built as part of your build system and the compilerโs source has not changed, or if the compiler only has changes that donโt affect code generation). You should only usenoneif you know what you are doing.string:valueโ Hashvalue. This can for instance be a compiler revision number or another string that the build system generates to identify the compiler.- a command string โ Hash the standard output and standard error output of the specified command. The string will be split on whitespace to find out the command and arguments to run. No other interpretation of the command string will be done, except that the special word
%compiler%will be replaced with the path to the compiler. Several commands can be specified with;as the separator. Examples:
%compiler% -v
%compiler% -dumpmachine; %compiler% -dumpversion
Okay so real talk about this one: make sure the command you give is as fast as it possibly can be, because ccache runs it once for every single ccache invocation. Every. Single. One. ๐
So why would you even want to identify the compiler with a command? Two big mood reasons:
- It's useful when you want to dodge cache misses after the compiler got rebuilt but didn't actually change. Same compiler, fresh mtime, no drama. โจ
- The other case is when the compiler ccache sees isn't the real compiler at all but another compiler wrapper on top. In that situation the default
mtimemethod hashes the mtime and size of that other wrapper, which means ccache literally can't tell when the compiler got upgraded. Using a suitable command to identify the compiler is safer, sure, but it's also slower โ so lowkey consider sticking with themtimemethod combined with theprefix_commandoption if you can. Go read USING CCACHE WITH OTHER COMPILER WRAPPERS for the whole story. ๐ซถ
compiler_type (CCACHE_COMPILERTYPE)
ccache normally just vibes its way into guessing the compiler type from the compiler's name. The compiler_type option lets you force the type instead. Iconic when your compiler has a non-standard name but is secretly one of the known types. Possible values:
autoโ guess one of the types below based on the compiler name (following symlinks). This is the default. ๐clangโ Clang-based compiler.clang-clโclang-cl.gccโ GCC-based compiler.iclโ Intel compiler on Windows.icxโ Intel LLVM-based compiler.icx-clโ Intel LLVM-based MSVC-compatible compiler.msvcโ Microsoft Visual C++ (MSVC).nvccโ NVCC (CUDA) compiler.qccโ QCC (QNX) compiler.otherโ any compiler other than the known types. ๐
compression (CCACHE_COMPRESS or CCACHE_NOCOMPRESS, see Boolean values above)
If true, ccache compresses the data it puts in the cache. โจ But heads up: this option does not affect how files are retrieved โ compressed and uncompressed results both stay perfectly usable no matter what you set here. Default is true.
The compression is done with the Zstandard algorithm, and it's fast enough that there's basically little reason to turn it off for performance. One exception: if your cache lives on a compressed file system, then ccache's compression is just redundant at that point. ๐ญ
Also, compression gets disabled if file cloning (the file_clone option) or hard linking (the hard_link option) is enabled. That's just how it is.
compression_level (CCACHE_COMPRESSLEVEL)
This one sets the level at which ccache compresses object files, using the real-time compression algorithm Zstandard. It only does anything if compression is enabled โ which it is, by default. ๐
Zstandard is extremely fast at decompressing and very fast at compressing on lower levels. Default is 0.
Semantics of compression_level, bestie:
> 0โ a positive value maps to normal Zstandard compression levels. Lower levels (e.g.1) mean faster compression but a worse compression ratio. Higher levels (e.g.19) mean slower compression but a better ratio. The max possible value depends on the libzstd version, but at least up to19is available on all versions. Decompression speed is essentially the same across all levels. Rule of thumb: use level5or lower, because higher levels can slow down compilations noticeably. Higher levels are still useful when recompressing the cache with the command line option-X/--recompress. ๐ฅ< 0โ a negative value maps to Zstandard's "ultra-fast" compression levels, which are even faster than level1but with less good ratios. For instance, level-3corresponds to--fast=3for thezstdcommand line tool. In practice there's little use for anything lower than-5or so.0(default) โ the value0means ccache picks a suitable level for you, currently1. ๐
See the Zstandard documentation at https://facebook.github.io/zstd/ for more info.
debug (CCACHE_DEBUG or CCACHE_NODEBUG, see Boolean values above)
If true, debug mode is on. ๐ Debug mode creates per-object debug files that are genuinely so helpful when you're debugging unexpected cache misses. But ngl, ccache performance drops slightly. See CACHE DEBUGGING. Default is false.
debug_dir (CCACHE_DEBUGDIR)
Tells ccache where to write those per-object debug files when debug mode is on. If set to the empty string, files get written right next to the object file. If set to a directory, the debug files are written with full absolute paths inside that directory, and ccache creates it if it's not there yet. Default is the empty string.
Example time, because this one's confusing: if debug_dir is set to /example, your current working directory is /home/user, and the object file is build/output.o, then the debug log lands at /example/home/user/build/output.o.ccache-log. ๐ฆ See also CACHE DEBUGGING.
debug_level (CCACHE_DEBUGLEVEL)
Sets how much info gets written when debug mode is enabled. See CACHE DEBUGGING. Default is 2.
depend_mode (CCACHE_DEPEND or CCACHE_NODEPEND, see Boolean values above)
If true, the depend mode is used. Default is false. See The depend mode.
direct_mode (CCACHE_DIRECT or CCACHE_NODIRECT, see Boolean values above)
If true, the direct mode is used. Default is true. See The direct mode. ๐
disable (CCACHE_DISABLE or CCACHE_NODISABLE, see Boolean values above)
When true, ccache just calls the real compiler and bypasses the cache completely. Default is false.
Bonus feature: you can also disable ccache for one specific source file by dropping the string ccache:disable in a comment within the first 4096 bytes of the file. Cute, right? ๐
extra_files_to_hash (CCACHE_EXTRAFILES)
A list of paths to files that ccache will include in the hash sum that identifies the build. Slap anything in here that should bust the cache.
file_clone (CCACHE_FILECLONE or CCACHE_NOFILECLONE, see Boolean values above)
If true, ccache attempts to use file cloning (also known as "copy on write", "CoW" or "reflinks") to store and fetch cached compiler results. file_clone takes priority over hard_link. Default is false. ๐ฆ
Files stored by cloning can't be compressed, so your cache size will likely get significantly larger if you enable this. That said, performance may improve depending on your use case.
Unlike the hard_link option, file_clone is completely safe to use โ it's just that not every file system supports the feature. On those, ccache falls back to plain copying (or hard links if hard_link is enabled). No cap. โจ
hard_link (CCACHE_HARDLINK or CCACHE_NOHARDLINK, see Boolean values above)
If true, ccache attempts to use hard links to store and fetch cached object files. Default is false.
Files stored via hard links can't be compressed either, so the cache size will likely be significantly larger with this on. Performance may improve depending on use case, butโ
โ ๏ธ Warning โ do not enable this option unless you're fully aware of these caveats:
- If the resulting file gets modified, the file in the cache gets modified too, since they share content โ which corrupts the cache entry. As of version
4.0, ccache makes stored and fetched object files read-only as a safety measure. On top of that, a simple integrity check runs on cached object files by verifying their sizes are correct. That means mistakes likestrip file.oorecho >file.oget detected even if the object file is made writable โ but a modification that doesn't change the file size? Not detected. ๐ - Programs that don't expect files from two different identical compilations to be hard links to each other can fail.
- Programs that rely on modification times (like
make) can get confused if several users (or one user with several build trees) share the same cache directory. The reason: object files share i-nodes, and therefore modification times. Iffile.ois in build tree A (hard-linked from the cache) andfile.othen gets produced by ccache in build tree B by hard-linking from the cache, the modification timestamp updates forfile.oin build tree A too. That can retrigger relinking in build tree A even though literally nothing really changed. ๐ญ
hash_dir (CCACHE_HASHDIR or CCACHE_NOHASHDIR, see Boolean values above)
If true (which is the default), ccache includes the current working directory (CWD) in the hash used to distinguish two compilations when generating debug info (compiler option -g with variations). Exception: the CWD is not included if the compiler options -fdebug-prefix-map or -fdebug-compilation-dir are used appropriately. See also the discussion under COMPILING IN DIFFERENT DIRECTORIES.
Why include the CWD by default? To prevent a problem with storing the current working directory in an object file's debug info โ which can lead ccache to hand you back a cached object file whose debug info has the working directory set incorrectly. ๐
You can disable this option to get cache hits when compiling the same source code in different directories, if you don't mind that the CWD in the debug info might be incorrect.
ignore_headers_in_manifest (CCACHE_IGNOREHEADERS)
A list of paths to files (or directories containing headers) that ccache will not include in the manifest list that makes up the direct mode. Lowkey important: this can cause stale cache hits if those headers do actually change. ๐
ignore_options(CCACHE_IGNOREOPTIONS) โ bestie, this is a space-delimited list of compiler options ccache is just gonnaโฆ ignore. Entries can optionally end with an asterisk (*) so they match any option suffix โ like,-fmessage-length=*matches both-fmessage-length=20and-fmessage-length=70. Slay. A matching compiler option will neither be interpreted specially nor be part of the input hash. Why would you ignore something from the hash? Honestly two moods: you know it doesn't affect the result (and ccache doesn't know that), or it does and you simply don't care. See also Extra options.inode_cache(CCACHE_INODECACHEorCCACHE_NOINODECACHE, see Boolean values above) โ If true, ccache caches source file hashes based on device, inode and timestamps. This lowkey reduces the time spent hashing include files since the result can be reused between compilations. Default is true. Heads up: the feature requirestemporary_dirto be on a local filesystem of a supported type.
Note โจ Support for the inode cache feature on Windows is experimental. On Windows the default is false. ๐
keep_comments_cpp(CCACHE_COMMENTSorCCACHE_NOCOMMENTS, see Boolean values above) โ If true, ccache will NOT discard the comments before hashing preprocessor output. Default is false. This can be used to check documentation with-Wdocumentation. ๐libexec_dirs(CCACHE_LIBEXEC_DIRS) โ If set, ccache looks for helper programs in these directories instead of the default. Simple as that, no cap.log_file(CCACHE_LOGFILE) โ If set to a file path, ccache writes info on what it's doing to that file. Super useful for tracking down problems (iykyk, debugging era). ๐ต๏ธโโ๏ธ
If set to syslog, ccache logs using syslog() instead of to a file. If you use rsyslogd, you can add something like this to /etc/rsyslog.conf or a file in /etc/rsyslog.d:
# log ccache to file
:programname, isequal, "ccache" /var/log/ccache
# remove from syslog
& ~
max_files(CCACHE_MAXFILES) โ Specifies the maximum number of files to keep in the cache. Use0for no limit (which is the default). See also CACHE SIZE MANAGEMENT.max_size(CCACHE_MAXSIZE) โ Specifies the maximum size of the cache. Use0for no limit. The default value is5GiB. Available suffixes:kB,MB,GB,TB(decimal) andKiB,MiB,GiB,TiB(binary). The default suffix isGiB. See also CACHE SIZE MANAGEMENT. ๐ฆmsvc_dep_prefix(CCACHE_MSVC_DEP_PREFIX) โ Specifies the prefix of included files output for the MSVC compiler. The default prefix is โNote: including file:โ. If you use a localized compiler, set this accordingly, okay? ๐msvc_utf8(CCACHE_MSVC_UTF8) โ This one adds/utf-8to themsvccommand line when executing the preprocessor, so filenames don't get garbled for non-ascii characters. Warning tho: this implicitly enables/validate-charsetand treats the source code as utf-8, which may cause compilation errors if comments in your code have characters in the[128, 255]range for a given Windows system codepage โ that results in an invalid utf-8 sequence. ๐ญ The default is true.namespace(CCACHE_NAMESPACE) โ If set, the namespace string gets added to the hashed data for each compilation. This makes the associated cache entries logically separate from cache entries with other namespaces, but bestie they still share the same storage space. Cache entries can also be selectively removed from the local cache with the command line option--evict-namespace, potentially in combination with--evict-older-than.
For instance, if you use the same local cache for several disparate projects, you can use a unique namespace string for each one. That way you can remove cache entries that belong to a certain project if you stop working with that project. Clean girl aesthetic for your cache. ๐งนโจ
path(CCACHE_PATH) โ If set, ccache searches directories in this list when looking for the real compiler. If not set, ccache looks for the first executable matching the compiler name in the normalPATHthat isn't a symbolic link to ccache itself.pch_external_checksum(CCACHE_PCH_EXTSUMorCCACHE_NOPCH_EXTSUM, see Boolean values above) โ When this is set and ccache finds a precompiled header file, ccache looks for a file with the extension โ.sumโ added (e.g. โpre.h.gch.sumโ), and if found, it hashes this file instead of the precompiled header itself โ working around the performance penalty of hashing very large files. Big brain move fr fr. ๐งprefix_command(CCACHE_PREFIX) โ Adds a list of prefixes (separated by space) to the command line that ccache uses when invoking the compiler. See also USING CCACHE WITH OTHER COMPILER WRAPPERS.prefix_command_cpp(CCACHE_PREFIX_CPP) โ Adds a list of prefixes (separated by space) to the command line that ccache uses when invoking the preprocessor. Same vibe, preprocessor edition. ๐ฆread_only(CCACHE_READONLYorCCACHE_NOREADONLY, see Boolean values above) โ If true, ccache attempts to use existing cached results, but will NOT add new results to any cache backend. Statistics counters will still be updated though, unless thestatsoption is set to false.
If you're doing this because your ccache directory is read-only, you need to set temporary_dir since ccache will fail to create temporary files otherwise. You may also want to set stats to false to make ccache not even try to update stats files. ๐
read_only_direct(CCACHE_READONLY_DIRECTorCCACHE_NOREADONLY_DIRECT, see Boolean values above) โ Just likeread_onlyexcept ccache will only try to retrieve results from the cache using the direct mode, not the preprocessor mode. See documentation forread_onlyregarding using a read-only ccache directory.recache(CCACHE_RECACHEorCCACHE_NORECACHE, see Boolean values above) โ If true, ccache will not use any previously stored result. New results will still be cached, possibly overwriting any pre-existing results. Out with the old, in with the new ๐remote_only(CCACHE_REMOTE_ONLYorCCACHE_NOREMOTE_ONLY, see Boolean values above) โ If true, ccache only uses remote storage. Default is false. Note that cache statistics counters will still be kept in the local cache directory unlessstatsis false. See also Storage interaction.remote_storage(CCACHE_REMOTE_STORAGE) โ Specifies one or several storage backends (separated by whitespace) to query after checking the local cache (unlessremote_onlyis true). See REMOTE STORAGE BACKENDS for docs on syntax and available backends.
Examples:
remote_storage = file:/shared/nfs/directory+`
remote_storage =
file:///shared/nfs/one read-only
file:///shared/nfs/two
remote_storage = file:///Z:/example/windows/folder
remote_storage = http://example.com/cache
remote_storage = redis://example.com
Note ๐ In previous ccache versions this option was calledsecondary_storage(CCACHE_SECONDARY_STORAGE), which can still be used as an alias.
reshare(CCACHE_RESHAREorCCACHE_NORESHARE, see Boolean values above) โ If true, ccache writes results to remote storage even for local storage cache hits. The default is false.response_file_format(CCACHE_RESPONSE_FILE_FORMAT) โ Ccache normally guesses the response file format based on the compiler type. This option lets you force the response file quoting behavior, which is useful if the compiler supports both POSIX and Windows response file quoting. Possible values are:autoโ Guess one of the formats below based on the compiler type. This is the default.posixโ POSIX quoting behavior.windowsโ Windows quoting behavior.
safe_dirs(CCACHE_SAFE_DIRS) โ A list of trusted directories for which directory-specific configuration files are allowed to set "unsafe options" (see Directory-specific configuration file). The default is empty.
Allowed list values: * matches any directory. An absolute path ending with /* matches any subdirectory (at any depth) under that path. An absolute path not ending in /* matches only that directory. ๐
sloppiness(CCACHE_SLOPPINESS) โ Okay so by default, ccache tries to give as few false cache hits as possible. But sometimes you know things ccache can't take for granted, and this option lets you tell ccache to relax some checks to increase the hit rate. Available values (separated by whitespace or comma):clang_index_storeโ Use case: Xcode projects with varying index store paths. Effect: Ignores the-index-store-pathand-index-unit-output-pathoptions when hashing. Trade-off: Index won't update correctly on cache hits.file_stat_matchesโ Use case: When file content checking is too slow. Effect: Uses file timestamps instead of content for cache validation. Trade-off: May miss content changes with identical timestamps.file_stat_matches_ctimeโ Use case: When controlling file timestamps manually. Effect: Ignores status change time whenfile_stat_matchesis enabled. Trade-off: May miss some file system changes.gcno_cwdโ Use case: Code coverage builds in different directories. Effect: Ignores current directory when creating.gcnofiles (-ftest-coverage). Also disables hashing of the current working directory if-fprofile-abs-pathis used. Trade-off: Directory information in coverage files may be incorrect.
Note ๐ซถ No effect with--coverage(it implies-fprofile-arcs).
incbinโ Use case: Projects using assembly.incbindirectives. Effect: Allows caching files with.incbindirectives. Trade-off: Won't detect changes to included binary files.include_file_ctimeโ Use case: Build systems that modify file timestamps frequently. Effect: Ignores file status change time when checking for recent modifications. Trade-off: May miss recent changes to source files.
include_file_mtimeโ bestie, use this when your build system is out here touching file timestamps like it's a nervous habit.- Use case: Build systems that modify file timestamps frequently.
- Effect: Ignores file modification time when checking for recent changes.
- Trade-off: May miss recent modifications to source files. ๐ฌ
ivfsoverlayโ for the Xcode girlies mixing things up.- Use case: Xcode projects mixing Objective-C and Swift.
- Effect: Ignores
-ivfsoverlayvirtual filesystem option. - Trade-off: May not detect VFS-related changes.
localeโ vibe check on your environment variables.- Use case: Builds in environments with varying locale settings.
- Effect: Ignores locale environment variables (
LANG,LC_ALL,LC_CTYPE,LC_MESSAGES). - Trade-off: Compiler warning messages may vary between cached and fresh builds.
modulesโ clang modules girlies, this one's for you ๐- Use case: Clang builds using
-fmodulesor-fprebuilt-implicit-modules. - Effect: Allows caching when C++ modules are used.
- Trade-off: May not detect changes in module internal state, or in implicitly built modules.
- See C++ MODULES for details.
- Use case: Clang builds using
pch_definesโ precompiled header moment.- Use case: Projects with precompiled headers.
- Effect: Relaxes checking of
#definedirectives in precompiled headers. - Trade-off: May not detect some macro definition changes.
- See PRECOMPILED HEADERS for details.
random_seedโ chaos but make it cacheable.- Use case: Builds with varying
-frandom-seedvalues. - Effect: Ignores random seed values in compilation hash.
- Trade-off: Builds may not be fully reproducible. ๐
- Use case: Builds with varying
system_headersโ for systems whose headers just won't sit still.- Use case: Systems with frequently changing system headers.
- Effect: Only tracks non-system headers in direct mode.
- Trade-off: Won't detect system header changes that affect compilation.
- Limitations: Only supported for GCC-like compilers (not MSVC). System headers are still checked in preprocessor mode.
- See also
ignore_headers_in_manifest.
time_macrosโ for the__DATE__girlies who literally do not care.- Use case: Code using time macros but values don't matter.
- Effect: Ignores
__DATE__,__TIME__, and__TIMESTAMP__in source. - Trade-off: Time values in output will be from cached compilation.
stats (CCACHE_STATS or CCACHE_NOSTATS, see Boolean values above)
If true, ccache will update the statistics counters on each compilation. The default is true. If false, automatic cleanup will be disabled as well. โจ (okay so turning stats off also turns off autocleanup, that's the tea, don't forget it)
stats_log (CCACHE_STATSLOG)
If set to a file path, ccache will write statistics counter updates to the specified file. This is useful for getting statistics for individual builds. To show a summary of the current stats log, use ccache --show-log-stats. ๐
Note Lines in the stats log starting with a hash sign (#) are comments.
temporary_dir (CCACHE_TEMPDIR)
This option specifies where ccache will put temporary files. The default is $XDG_RUNTIME_DIR/ccache-tmp (typically /run/user/<UID>/ccache-tmp) if XDG_RUNTIME_DIR is set and the directory exists, otherwise <cache_dir>/tmp.
Note In previous versions of ccache,CCACHE_TEMPDIRhad to be on the same filesystem as theCCACHE_DIRpath, but this requirement has been relaxed. ๐
umask (CCACHE_UMASK)
This option (an octal integer) specifies the umask for files and directories in the cache directory. This is mostly useful when you wish to share your cache with other users. ๐ซถ (sharing is caring, fr fr)
๐ซ Disabling ccache
To disable ccache completely for all invocations, set disable = true (CCACHE_DISABLE=1). You can also disable ccache for a certain source code file by adding the string ccache:disable in a comment in the first 4096 bytes of the file. In the latter case the Ccache disabled statistics counter will be increased. ๐
โ๏ธ REMOTE STORAGE BACKENDS โ๏ธ
The remote_storage option lets you configure ccache to use one or several remote storage backends. By default, the local cache directory located in cache_dir will be queried first and remote storage second, but remote_only can be set to true to disable local storage. Note that cache statistics counters will still be kept in the local cache directory โ remote storage backends only store compilation results and manifests. no cap โจ
๐ง Storage helper process
ccache can spawn a long-lived local storage helper process (installed separately) to handle communication with the remote storage. Storage helpers keep remote connections up for efficiency and terminate after a while on inactivity. See Storage helpers at https://ccache.dev/storage-helpers.html for a list of known helpers.
The storage helper program is called ccache-storage-<scheme>, where <scheme> is the scheme part of a URL, e.g. https. The program can be placed in these locations (in priority order):
- In a location specified by the
helperproperty (see below). - In a
libexecdirectory. - Next to the ccache executable.
- In
$PATH.
If the program is not found, ccache falls back to one of the builtin backends if available, otherwise ccache exits with an error. ๐ญ
๐ Configuration syntax
A remote storage backend is specified by a URL and can be followed by a whitespace-separated list of properties (key=value) and custom attributes (@key=value). A missing =value is shorthand for setting the value to true. Values must be percent-encoded (see https://en.wikipedia.org/wiki/Percent-encoding) if they contain %, | or whitespace characters. For compatibility with older ccache versions, | characters are treated as spaces.
๐ Properties
data-timeout: Timeout for send/receive data transfer. Resets whenever data is received or can be sent. Default:10s.helper: Override which storage helper to spawn (either a filename or a full path). This is mainly useful when developing or testing new helpers.idle-timeout: Timeout for the helper process to wait before exiting after client inactivity (0s: stay up indefinitely). Default:10m.read-only: If true, only read from this backend, don't write. The default isfalse.request-timeout: Timeout for the whole request. Default:1m.shards: A comma-separated list of names for sharding (partitioning) the cache entries using Rendezvous hashing (seehttps://en.wikipedia.org/wiki/Rendezvous_hashing), typically to spread the cache over a server cluster. When set, the storage URL must contain an asterisk (*), which will be replaced by one of the shard names to form a real URL. A shard name can optionally have an appended weight within parentheses to indicate how much of the key space should be associated with that shard. A shard with weight w will contain w/S of the cache, where S is the sum of all shard weights. A weight could for instance be set to represent the available memory for a memory cache on a specific server. The default weight is1.
Examples:
http://cache-*.example.com shards=a(3),b(1),c(1.5)will put 55% (3/5.5) of the cache onhttp://cache-a.example.com, 18% (1/5.5) onhttp://cache-b.example.comand 27% (1.5/5.5) onhttp://cache-c.example.com. ๐ฅhttp://example.com/* shards=alpha,betawill put 50% of the cache onhttp://example.com/alphaand 50% onhttp://example.com/beta.
Timeouts can be specified with an ms (milliseconds), s (seconds), m (minutes), h (hours) or d (days) suffix. โฑ๏ธ
๐ Custom attributes
Custom attributes on the form @key=value are specific to each storage helper implementation. See the backend's documentation for which attributes are available. Examples:
file:///example/directory @umask=002 @update-mtime=truehttps://example.com/path @bearer-token=deadbeef
๐ Storage interaction
The list below describes the interaction between local and remote storage on cache hits and misses if remote_only is false (which is the default):
- Local storage: miss, remote storage: miss โ Compile, write to local, write to remote[1]
- Local storage: miss, remote storage: hit โ Read from remote, write to local
- Local storage: hit, remote storage:
-โ Read from local, don't write to remote[2]
[1] Unless remote storage has property read-only=true.
[2] Unless local storage is set to share its cache hits with the reshare option. ๐
If remote_only is true, here's the whole mood ๐
- local:
-(nothing), remote: miss โ compile it, write it to remote, and do not write to local storage. Bestie, the local cache stays untouched, periodt. - local:
-(nothing), remote: hit โ read it straight from remote, and again, don't write to local.
๐ธ File storage backend ๐ธ
URL format: file:DIRECTORY or file://[HOST]DIRECTORY
This one stores data as separate files in a directory structure below DIRECTORY, which is similar to (but not identical to) the local cache storage, okurrr. A classic use case is sharing a cache on an NFS directory. DIRECTORY must start with a slash. HOST can be the empty string or localhost. On Windows, HOST can also be the name of a server hosting a shared folder. ๐ซถ
โ ๏ธ Important: ccache will not perform any cleanup of the storage โ that has to be done by other means, for instance by running ccache --trim-dir periodically. So like, don't expect it to tidy up after itself, because it won't. ๐
Examples:
file:/shared/nfs/directoryfile:///shared/nfs/directory @umask=002 @update-mtime=truefile:///Z:/example/windows/folderfile://example.com/shared/ccache%20folder
Optional attributes:
@layoutโ how to store files under the cache directory. Available values:flatโ store all files directly under the cache directory.localโ read files using the dynamic directory layout of the local cache. This layout is intended for a one-way copy or read-only mount of a local cache directory, and it makes the file storage backend read-only. The directory must contain self-contained entries (file_cloneorhard_linkare not supported). ๐ซsubdirsโ store files in 256 subdirectories of the cache directory.- The default is
subdirs.
@umaskโ this attribute (an octal integer) overrides the umask to use for files and directories in the cache directory.@update-mtimeโ iftrue, update the modification time (mtime) of cache entries that are read. The default isfalse.
๐ง CRSH storage backend ๐ง
URL format: crsh:IPC_ENDPOINT
This backend connects to an already-running ccache storage helper (CRSH) process that's listening on IPC_ENDPOINT (a Unix socket path or a Windows named pipe). The use case here is mainly when you're developing or debugging a storage helper, or in special setups where the helper program is started and managed externally. Very behind-the-scenes, very main character energy. โจ
Examples:
crsh:/path/to/your.sock(Unix socket)crsh:name-of-your-pipe(Windows named pipe)
๐ HTTP storage backend ๐
๐จ Warning: Built-in support for the HTTP protocol is deprecated and will be removed in the next non-bug-fix ccache version. Use a remote storage helper instead. Like, it's giving end of an era. ๐ญ
URL format: http://HOST[:PORT][/PATH]
This backend stores data in an HTTP-compatible server. The required HTTP methods are GET, PUT and DELETE. That's the whole bar to clear, ngl.
โ ๏ธ Important: ccache will not perform any cleanup of the storage โ that has to be done by other means, for instance by running ccache --trim-dir periodically.
๐ Note: HTTPS is not supported. I know. I know. ๐
๐ก Tip: See How to set up HTTP storage at https://ccache.dev/howto/http-storage.html for hints on how to set up an HTTP server for use with ccache.
Examples:
http://localhosthttp://someusername:p4ssw0rd@example.com/cache/http://localhost:8080 @layout=bazel
Optional attributes:
@bearer-tokenโ bearer token used to authorize the HTTP requests.@keep-aliveโ iftrue, keep the HTTP connection to the storage server open to avoid reconnects. The default istrue.@layoutโ how to map key names to the path part of the URL. Available values:bazelโ store values in a format compatible with the Bazel HTTP caching protocol. More specifically, the entries will be stored as 64 hex digits under the/ac/part of the cache.
๐ Note: You may have to disable verification of action cache values in the server for this to work, since ccache entries are not valid action result metadata values. Yeah. Awkward. ๐
flatโ append the key directly to the path part of the URL (with a leading slash if needed).subdirsโ append the first two characters of the key to the URL (with a leading slash if needed), followed by a slash and the rest of the key. This divides the entries into 256 buckets.- The default is
subdirs.
@headerโ add thekey=valuepair to the HTTP headers of the request. For example:@header=Content-Type=application/octet-streamadds"Content-Type: application/octet-stream"to the HTTP headers of the request.
๐ Redis storage backend ๐
๐จ Warning: Built-in support for the Redis protocol is deprecated and will be removed in the next non-bug-fix ccache version. Use a remote storage helper instead.
URL formats:
redis://[[USERNAME:]PASSWORD@]HOST[:PORT][/DBNUMBER]
redis+unix:SOCKET_PATH[?db=DBNUMBER]
redis+unix://[[USERNAME:]PASSWORD@localhost]SOCKET_PATH[?db=DBNUMBER]
This backend stores data in a Redis (or Redis-compatible) server. There are implementations for both memory-based and disk-based storage. PORT defaults to 6379 and DBNUMBER defaults to 0. Slay. ๐ฅ
๐ Note: ccache will not perform any cleanup of the Redis storage, but you can configure LRU eviction.
๐ก Tip: See How to set up Redis storage at https://ccache.dev/howto/redis-storage.html for hints on setting up a Redis server for use with ccache.
๐ก Tip: You can set up a cluster of Redis servers using the shards property described in REMOTE STORAGE BACKENDS.
Examples:
redis://localhostredis://p4ssw0rd@cache.example.com:6379/0redis+unix:/run/redis.sockredis+unix:///run/redis.sockredis+unix://p4ssw0rd@localhost/run/redis.sock?db=0
๐ CACHE SIZE MANAGEMENT ๐
So by default, ccache has a 5 GB limit on the total size of files in the cache, and no limit on the number of files. You can set different limits using the command line options -M/--max-size and -F/--max-files. Use the -s/--show-stats option to see the cache size and the currently configured limits (in addition to other various statistics). Look at her go. ๐
Cleanup can be triggered in two different ways: automatic and manual.
๐ Automatic cleanup ๐
After a new compilation result has been stored in the local cache, ccache will trigger an automatic cleanup if max_size or max_files is exceeded. The cleanup removes cache entries in approximate LRU (least recently used) order, based on the modification time (mtime) of files in the cache. For this reason, ccache updates the mtime of the cache files read on a cache hit to mark them as recently used. It's literally keeping receipts of who was here last. ๐ต๏ธ
For performance reasons, only entries in a subset of the cache are considered when automatic cleanup is triggered, so the oldest entries aren't always removed first โ but the overall behavior approximates LRU over time. So it's vibes-based LRU, but the vibes are, like, correct on average. ๐
๐ฆ Manual cleanup ๐ฆ
Run ccache --cleanup to force cleanup of the whole cache. This will recalculate the cache size information and make sure that the cache size does not exceed max_size and max_files.
Note that there is no guarantee that only the oldest entries are evicted, as discussed in Automatic cleanup above. To evict based on age, use ccache --evict-older-than AGE. That's the one you want if you're being picky about age. ๐
๐ฅ CACHE COMPRESSION ๐ฅ
By default, ccache compresses all cached data using the Zstandard (zstd) algorithm at compression level 1. This algorithm is fast enough that compression rarely impacts performance. You might want to disable compression only if your cache is stored on an already-compressed filesystem, where ccache's compression would be redundant. Like wearing two jackets. ๐งฅ๐งฅ
For configuration details, see compression and compression_level.
Use ccache --show-compression to display compression information. Example output:
Total data: 14.8 GB (16.0 GB disk blocks)
Compressed data: 11.3 GB (30.6% of original size)
Original size: 36.9 GB
Compression ratio: 3.267 x (69.4% space savings)
Incompressible data: 3.5 GB
Notes, bestie, take these in:
- Disk blocks โ the actual cache size accounting for filesystem block size. This should match the "Cache size" from
ccache --show-stats. - Compressed data โ result and manifest files stored in the cache.
- Incompressible data โ files stored without compression (due to
file_cloneorhard_linksettings) or legacy files from older ccache versions. Old money, basically. ๐๏ธ - Compression ratio โ affected by
compression_level.
You can recompress cached data to different compression levels using ccache --recompress. Only files with different compression levels than the target will be recompressed. No wasted effort, we love efficiency. โญ
โญ CACHE STATISTICS โญ
ccache --show-stats shows a summary of statistics, including cache size, cleanups (number of performed cleanups, either implicitly due to a cache size limit being reached or due to explicit ccache -c calls), overall hit rate, hit rate for direct/preprocessed modes, and hit rate for local and remote storage. It's the whole story of your cache in one screen, and honestly? Iconic. ๐
Okay so real talk: those statistics counters? ccache itself literally does not touch them during builds. Like, not even a little. Which means you can safely reset them whenever you want with ccache --zero-stats and your build will not care at all โ no cap, zero drama, the build process stays completely unaffected. ๐
Why would you even want to do that? Say you're about to run a build and you want ccache --show-stats to summarize only that specific build. Just zero the counters first and you're golden. โจ
Bestie tip: resetting is totally safe, but it does wipe the lifetime numbers โ so pick your moment.
Orrrr, if you'd rather keep the lifetime stats intact, you can set stats_log before starting the build and then run ccache --show-log-stats afterward to peep build-specific statistics. ๐ This approach is honestly kind of iconic: the statistics counters keep tracking the entire lifetime of the cache the whole time, and you still get detailed info for individual builds. Both. At once. Main character energy. ๐
And there's another advantage of stats_log too โ it collects statistics without any interference from other concurrent builds that are accessing the same cache. ๐ฆ So if your machine is out here running multiple builds at the same time, your numbers stay clean and yours. Periodt. ๐
The summary also has โErrorsโ and โUncacheableโ counters, and bestie, those are literally just sums of the more detailed counters below ๐
so if you wanna see the receipts, just hit -v/--verbose and the verbose mode will spill all of these for you:
- Autoconf compile/link โ an uncacheable compilation or linking done by an Autoconf test. like, the test was just vibing and ccache couldn't cache it ๐ซ
- Bad compiler arguments โ malformed compiler argument, e.g. missing a value for a compiler option that requires an argument, or failure to read a file specified by a compiler option argument. the syntax was giving broken ๐
- Called for linking โ the compiler was called for linking, not compiling. ccache only supports compilation of a single file, i.e. calling the compiler with the
-coption to produce a single object file from a single source file. so yeah, we're not doing that linky thing โจ - Called for preprocessing โ the compiler was called for preprocessing, not compiling. respectfully, not our department ๐
- Ccache disabled โ ccache was disabled by a
ccache:disablestring in the source code file. the source file literally said "not me" ๐ญ - Could not use modules โ the preconditions for using C++ MODULES were not fulfilled. modules said "i'm busy" ๐
- Could not use precompiled header โ the preconditions for using precompiled headers were not fulfilled. no precompiled header for you today, bestie ๐ธ
- Could not read or parse input file โ an input file could not be read or parsed (see the debug log for details). the debug log is where the tea is โ
- Could not write to output file โ the output path specified with
-ocould not be written to. lowkey blocked ๐ซ - Compilation failed โ the compilation failed. no result stored in the cache. it flopped, and we do not cache flops ๐
- Compiler check failed โ a compiler check program specified by
compiler_check(CCACHE_COMPILERCHECK) failed. the vibe check did not pass ๐ - Compiler output file missing โ one of the files expected to be produced by the compiler was missing after compilation. it was supposed to be there and then... wasn't ๐ป
- Compiler produced empty output โ the compiler's output file (typically an object file) was empty after compilation. zero bytes, zero thoughts, head empty ๐ซถ
- Could not find the compiler โ the compiler to execute could not be found. where did it go. genuinely where ๐ง
- Error hashing extra file โ failure reading a file specified by
extra_files_to_hash(CCACHE_EXTRAFILES). couldn't hash it, so we couldn't help it ๐ญ - Forced recache โ
CCACHE_RECACHEwas used to overwrite an existing result. we said do it again and it ATE ๐ฅ - Input file modified during compilation โ an input file was modified during compilation. rude, honestly, we were mid-compile ๐
- Internal error โ unexpected failure, e.g. due to problems reading/writing the cache. the cache was acting up, iconic but not in a good way ๐
- Missing cache file โ a file was unexpectedly missing from the cache. this only happens in rare situations, e.g. if one ccache instance is about to get a file from the cache while another instance removed the file as part of cache cleanup. so like, one girl was grabbing it while another girl was decluttering โ tragic timing ๐ญ
- Multiple source files โ the compiler was called to compile multiple source files in one go. this is not supported by ccache. one at a time, we're not doing a group project ๐ โโ๏ธ
- No input file โ no input file was specified to the compiler. nothing to compile, babe. an empty plate ๐ฝ๏ธ
- Output to stdout โ the compiler was told to write its output to standard output with
-o -. Ccache does not support this, sorry bestie. - Preprocessing failed โ preprocessing the source code with the compiler's
-Eoption just... did not work. - Unsupported code directive โ something like the assembler
.incbindirective showed up in the code. Ccache does not support that. - Unsupported compiler option โ a compiler option that ccache doesn't support got used.
- Unsupported environment variable โ an environment variable that ccache doesn't support was set.
- Unsupported source encoding โ the source file (or one of the included headers) has an encoding ccache can't deal with. Right now ccache needs UTF-8-encoded source code for MSVC when
msvc_utf8is true. That's the rule, no cap. - Unsupported source language โ a source language, like the one you'd set with
-x, that ccache doesn't support.
โจ HOW CCACHE WORKS โจ
Okay so here's the whole vibe ๐ ccache peeps when you're compiling the same code twice and just reuses the output it already stashed. How? It builds a unique hash โ the "input hash" โ out of all the info that actually affects the compilation. Then when that exact same hash shows up again, ccache can hand you back all the correct compiler outputs straight from the cache. Iconic behaviour, honestly.
For the hashing itself, ccache uses BLAKE3 (the one at https://blake3.io), which is a fast cryptographic hash algorithm. And for data integrity, cached data is protected with XXH3 (over at https://xxhash.com) checksums so corruption gets caught. ๐ก๏ธ
Ccache has two strategies for gathering the info that goes into cache lookup keys:
- Preprocessor mode โ ccache runs the preprocessor on the source code and hashes the result.
- Direct mode โ ccache hashes the source code and the include files directly.
Direct mode is generally faster because it skips the overhead of running the preprocessor. Speed queen behaviour. โก
When direct mode doesn't find a cached result (that's a cache miss, fyi), ccache falls back to preprocessor mode โ unless depend mode is enabled. In depend mode, ccache never runs the preprocessor, not even on cache misses. See The depend mode below for the deets ๐ซถ
๐ธ Common hashed information ๐ธ
This info is always in the hash, every single time:
- the extension the compiler uses for a file with preprocessor output (normally
.ifor C code and.iifor C++ code) - the compiler's size and modification time (or other compiler-specific info specified by
compiler_check) - the name of the compiler
- the current directory (if
hash_diris enabled) - contents of files specified by
extra_files_to_hash(if there are any)
๐ The preprocessor mode ๐
In preprocessor mode, the hash is made of the common info plus:
- the preprocessor output from running the compiler with
-E - the command line options, except the ones that affect include files (
-I,-include,-D, etc. โ the theory being that those command line options will change the preprocessor output if they have any effect at all) - any standard error output the preprocessor generated
Based on that hash, the cached compilation result can be looked up directly in the cache. Easy. ๐
๐ฆ The direct mode ๐ฆ
In direct mode, the hash is made of the common info plus:
- the input source file
- the compiler options
Based on that hash, ccache looks up a data structure in the cache called a "manifest". That manifest contains:
- references to cached compilation results (object file, dependency file, etc.) that previous compilations matching the hash produced
- paths to the include files that were read back when those compilation results got stored in the cache
- hash sums of the include files at the time those compilation results were stored in the cache
Then the current contents of the include files get hashed and compared against the manifest. Match? ccache already knows the result of the compilation, slay. No match? ccache falls back to running the preprocessor. The preprocessor output gets parsed to find which include files were read, and the paths plus hash sums of those include files get stored in the manifest alongside info about the compilation result that was produced.
Okay so there's a catch with direct mode ๐ header files that the compiler did use get recorded, but header files that it did not use โ but would have used if they'd existed โ do not. To soften that problem, ccache records whether directories specified with -I and similar exist at the time of compilation, which handles most cases. Still, when ccache checks whether a result can be taken from the cache, it currently can't check with 100% accuracy whether the existence of a new header file should invalidate the result. In practice though, direct mode is safe to use in the absolute majority of cases. ๐
Direct mode gets disabled if any of these hold:
direct_modeis false- a modification time of one of the include files is too new (needed to avoid a race condition)
- a compiler option not supported by direct mode is used, for example:
- a
-Wp,*compiler option other than-Wp,-MD,<path>,-Wp,-MMD,<path>,-Wp,-D<macro[=defn]>or-Wp,-U<macro> - most uses of
-Xpreprocessor
- a
- the string
__TIME__is present in the source code
๐ The depend mode ๐
If depend mode is enabled, ccache will not use the preprocessor at all. The hash used to identify results in the cache is based on the direct mode hash described above, plus info about include files read from the dependency list generated by MSVC with /showIncludes, or the dependency file generated by other compilers with -MD or -MMD.
Advantages:
- The ccache overhead of a cache miss will be much smaller.
- Not running the preprocessor at all can be a good thing if compilation happens remotely, for instance when using distcc or similar โ ccache then won't make potentially costly preprocessor calls on the local machine. ๐ซ
Disadvantages:
- The cache hit rate will likely be lower, since any change to compiler options or source code makes the hash different. Compare that to the default setup, where ccache falls back to preprocessor mode, which is tolerant to some types of changes in compiler options and source code.
- If
-MDis used, the manifest entries will include system header files too, which slows down cache hits slightly, just like using-MDslows down make. Same deal for MSVC with/showIncludes. - If
-MMDis used, the manifest entries will not include system header files, which means ccache will ignore changes in them. ๐ฌ
Depend mode gets disabled if any of these hold:
depend_modeis false.- The compiler is not generating dependencies using
-MDor-MMD(for MSVC,/showIncludesis added automatically if the user didn't specify it).
โญ HANDLING OF NEWLY CREATED SOURCE FILES โญ
Okay so if the modification time (mtime) or status change time (ctime) of the source file โ or of any of the include files โ is equal to (or newer than) the time ccache was invoked, ccache disables caching completely. Yeah, all of it. This is a safety measure to avoid a race condition (see below). In practice it only bites you when you're on file systems with very low timestamp granularity. You can set sloppiness to include_file_ctime,include_file_mtime to opt out of the safety measure. ๐ง
For reference, that race condition I mentioned consists of these events:
- A source code file is read by ccache and added to the input hash.
- The source code file is modified.
- The compiler is executed and reads the modified source code.
- Ccache stores the compiler output in the cache associated with the incorrect key (the one based on the unmodified source code). ๐
Not the vibe. Protect your timestamps, bestie. ๐ซถ
๐ CACHE DEBUGGING ๐
okay so if you're sitting there like "why am I not getting cache hits, what is ccache even hashing??" โ bestie, same. The answer: turn on debug mode via the config option debug, or by setting CCACHE_DEBUG in the environment. It's literally made for investigating why you don't get cache hits. Just know that performance will be reduced slightly, ngl. A little sacrifice ๐
When debug mode is on, ccache will create up to five additional files next to the object file:
<objectfile>.<timestamp>.ccache-input-cโ debug level2. Binary input hashed by both the direct mode and the preprocessor mode. ๐ค<objectfile>.<timestamp>.ccache-input-dโ debug level2. Binary input only hashed by the direct mode.<objectfile>.<timestamp>.ccache-input-pโ debug level2. Binary input only hashed by the preprocessor mode.<objectfile>.<timestamp>.ccache-input-textโ debug level2. Human-readable combined diffable text version of the three files above. This one's the โจ icon โจ<objectfile>.<timestamp>.ccache-logโ debug level1. Log for this object file.
The timestamp format is:
<year><month><day>_<hour><minute><second>_<microsecond>
If you only need the log file (valid, honestly), set debug_level (environment variable CCACHE_DEBUGLEVEL) to 1.
And if debug_dir (environment variable CCACHE_DEBUGDIR) is set, the files above will be written to that directory with full absolute paths instead of next to the object file. Slay, organized.
Okay so here's the hashing tea โ In the direct mode, ccache uses the 160 bit BLAKE3 hash of the "ccache-input-c" + "ccache-input-d" data (where + means concatenation), while the "ccache-input-c" + "ccache-input-p" data is used in the preprocessor mode.
The "ccache-input-text" file is a combined text version of the three binary input files. It has three sections ("COMMON", "DIRECT MODE" and "PREPROCESSOR MODE"), which in turn contain annotations that say what kind of data comes next. Fr fr, it's giving annotated anthology.
To debug why you don't get an expected cache hit for an object file, you can do something like this:
- Enable debug (
CCACHE_DEBUG). - Build.
- Clean and build again.
- Compare the
<objectfile>.<timestamp>.ccache-input-textfiles for the two builds. This together with the<objectfile>.<timestamp>.ccache-logfiles should give you some clues about what is happening.
That's the whole ritual. Detective era ๐
๐ COMPILING IN DIFFERENT DIRECTORIES ๐
When compiling the same source code in different directories, ccache often can't share cached results if absolute paths become part of the input hash. Tragic, I know ๐ญ These paths appear in:
- preprocessed source code (when using
-gfor debug info or absolute paths in-Ioptions) - command-line arguments (absolute paths to source files or include directories)
- macro expansions (
__FILE__macros and preprocessor warnings)
To enable cache sharing across different build directories for debug builds (using -g), normalize debug paths, e.g. with GCC option -fdebug-prefix-map=$PWD=. (map current directory to relative) or -fdebug-compilation-dir=. (set compilation directory). Alternatively, set hash_dir to false (disables directory hashing).
For builds with absolute paths, set base_dir to a common parent directory. Ccache will convert absolute paths under this directory to relative paths before hashing. Big brain move ๐ง โจ
For example, if projects are in /home/user/projects, set base_dir to /home/user/projects or just /home/user.
๐ง PRECOMPILED HEADERS ๐ง
Ccache has limited support for precompiled headers (PCH) with GCC and Clang. Limited! Read the fine print bestie, don't come for me.
Required configuration:
- Set
sloppinesstopch_defines,time_macros- This is needed because ccache can't detect time macro usage or
#definechanges when using PCH. - Consider adding
include_file_mtime,include_file_ctimefor newly created files (see HANDLING OF NEWLY CREATED SOURCE FILES).
- This is needed because ccache can't detect time macro usage or
- One of:
- GCC/Clang: Use
-include header(don't use#includein source; the filename must be sufficient to find the header). - Clang only: Use
-include-pchwith the generated PCH file. - GCC only: Add
-fpch-preprocesswhen compiling.
- GCC/Clang: Use
- For Clang, add
-fno-pch-timestampto disable timestamp checks.
Troubleshooting (aka when it goes sideways ๐):
- Without proper setup, ccache falls back to the non-precompiled header (if available).
- If no fallback exists, you'll see "Preprocessing failed" in statistics.
- Files using
#pragma onceinstead of include guards may cause issues.
๐ C++ MODULES ๐
Ccache does currently not support standard C++20 modules. Say it with me: no cap, not supported.
There is however limited support for "Clang modules" (the -fmodules option) with these requirements:
- Set
sloppinesstomodules. - Enable both direct mode and depend mode.
This is how it works:
- Ccache hashes
module.modulemapfiles but ignores Clang's binary module cache. - This works because identical
module.modulemapfiles should produce compatible cached results.
Note The preprocessor mode doesn't provide enough information for module support depend mode. When using the preprocessor mode Clang does not provide enough information to allow hashing of module.modulemap files. ๐
๐ Explicit module files ๐
Regardless of the above, ccache hashes the module files that a compilation reads, so that a consumer is recompiled when a module it imports changes. This works for the options that tell ccache which files those are:
-fmodule-file=, which gives the path directly.-fprebuilt-module-path=, whose directory Clang searches for<module-name>.pcm. The command line doesn't say which of those files the compilation reads, so all of them are hashed, names as well as contents. This costs a hit when an unrelated module file in the same directory changes. Annoying but honest ๐ซ
-fprebuilt-implicit-modules compilations are counted as "Could not use modules" unless sloppiness is set to modules. Clang looks up implicit modules in a subdirectory layout named by hashes of compiler internals, so ccache can't tell which files the compilation reads.
๐ซถ SHARING A LOCAL CACHE ๐ซถ
A group of developers can increase the cache hit rate by sharing a local cache directory. Bestie group project energy ๐ To share a local cache without unpleasant side effects, the following conditions should to be met:
- Use the same cache directory.
- Make sure that the configuration option
hard_linkisfalse(which is the default). - Make sure that all users are in the same group.
- Set the configuration option
umaskto002. This ensures that cached files are accessible to everyone in the group. - Make sure that all users have write permission in the entire cache directory (and that you trust all users of the shared cache).
- Make sure that the setgid bit is set on all directories in the cache. This tells the filesystem to inherit group ownership for new directories. The following command might be useful for this:
find $CCACHE_DIR -type d | xargs chmod g+s
The reason to avoid the hard link mode is that the hard links cause unwanted side effects, as all links to a cached file share the file's modification timestamp. This results in false dependencies to be triggered by timestamp-based build systems whenever another user links to an existing file. Typically, users will see that their libraries and binaries are relinked without reason. Not the vibe ๐ค
You may also want to make sure that a base directory is set appropriately, as discussed in a previous section.
๐ SHARING A CACHE ON NFS ๐
Okay so you can put the cache directory on an NFS filesystem (or a similar filesystem), but bestie, keep these in mind first:
- Having the cache on NFS may slow down compilation. Do some benchmarking to see if it's even worth it, fr.
- Ccache hasn't been tested very thoroughly on NFS. Just so you know what you're walking into. ๐
A tip: set temporary_dir to a directory on the local host so temporary files don't generate NFS traffic. Chef's kiss move. โจ
It is recommended to use the same operating system version when using a shared cache. If the operating system versions are different then system include files will likely be different, and there'll be few or no cache hits between the systems. One way of improving the cache hit rate in that case is to set sloppiness to system_headers to ignore system headers. ๐
An alternative to putting the main cache directory on NFS? Set up a remote storage file cache. Iconic. ๐
๐ซถ USING CCACHE WITH OTHER COMPILER WRAPPERS ๐ซถ
The recommended way of combining ccache with another compiler wrapper (such as "distcc") is by letting ccache execute the compiler wrapper. Yes, ccache is the main character here. ๐
You do this by defining prefix_command, for example by setting the environment variable CCACHE_PREFIX to the name of the wrapper (e.g. distcc). Ccache will then prefix the command line with the specified command when running the compiler. And if you want to specify several prefix commands, set prefix_command to a space-separated list of commands.
Unless you set compiler_check to a suitable command (peep the description of that configuration option), it is not recommended to use the form ccache anotherwrapper compiler args as the compilation command. It's also not recommended to use the masquerading technique for the other compiler wrapper. The reason is that by default, ccache will in both cases hash the mtime and size of the other wrapper instead of the real compiler, which means that:
- Compiler upgrades will not be detected properly. ๐ญ
- The cached results will not be shared between compilations with and without the other wrapper.
Another minor thing: if prefix_command is used, ccache will not invoke the other wrapper when running the preprocessor, which increases performance. You can use prefix_command_cpp if you also want to invoke the other wrapper when doing preprocessing (normally by adding -E). ๐ฆ
โ ๏ธ CAVEATS โ ๏ธ
- The direct mode fails to pick up new header files in some rare scenarios. See The direct mode above. ๐
๐ฉบ TROUBLESHOOTING ๐ฉบ
General
To understand what ccache is doing you can enable debug logging by setting debug to true or using the environment variable CCACHE_DEBUG=1. See CACHE DEBUGGING for details. ๐
You can also use ccache -s to view cache hit rates, miss reasons and other performance metrics. Literally your new best friend.
Performance
Ccache is designed to work well with minimal configuration, but you can optimize performance further: ๐
- Place the cache directory on fast storage (SSD preferred).
- Ensure sufficient RAM so cached files stay in the filesystem cache.
- Consider using remote storage for sharing the cache.
To monitor cache effectiveness, compare ccache -s output before and after builds to identify issues.
If "preprocessed cache hits" increases instead of "direct cache hits", ccache is falling back to the slower preprocessor mode. Causes include:
- source code changes that don't affect preprocessor output
- changes to include-related options (
-I,-include,-D) that don't change the actual preprocessed code - using unsupported preprocessor options like
-Xpreprocessoror-Wp,*(except-Wp,-MD,<path>,-Wp,-MMD,<path>,-Wp,-D<define>) - first compilation after changing
base_dir - include files with timestamps newer than ccache startup (see HANDLING OF NEWLY CREATED SOURCE FILES)
- code containing
__TIME__,__DATE__, or__TIMESTAMP__forces preprocessor mode (if these macros aren't actually used or you don't need current values, setsloppinesstotime_macros) - input file path changes (affects
__FILE__macro expansion)
If identical code doesn't produce cache hits, these are some possible causes: ๐ธ
- time/date macros or generated code with timestamps/build counters
- cache cleanup due to size limits
- environment differences affecting compilation
Common error counters:
- "Multiple source files": The compiler was called with multiple source files at once (not supported by ccache).
- "Unsupported compiler option": Enable debug logging to see which option was rejected.
- "Preprocessing failed": Could indicate precompiled header issues (see PRECOMPILED HEADERS).
- "Could not use precompiled header": See PRECOMPILED HEADERS for setup requirements.
- "Could not use modules": See C++ MODULES for configuration needs and check which compiler option was rejected.
Corrupt object files
It should be noted that ccache is susceptible to general storage problems. If a bad object file sneaks into the cache for some reason, it will of course stay bad. Some possible reasons for erroneous object files are bad hardware (disk drive, disk controller, memory, etc), buggy drivers or file systems, a bad prefix_command or compiler wrapper. If this happens, the easiest way of fixing it is this:
- Build so that the bad object file ends up in the build tree.
- Remove the bad object file from the build tree.
- Rebuild with
CCACHE_RECACHEset.
An alternative is to clear the whole cache with ccache -C if you don't mind losing other cached results. ๐ซฃ
There are no reported issues about ccache producing broken object files reproducibly. That doesn't mean it can't happen, so if you find a repeatable case, please report it! We wanna know. ๐
๐ MORE INFORMATION ๐
Credits, mailing list information, bug reporting instructions, source code, etc, can be found on ccache's web site: https://ccache.dev.
๐ AUTHOR ๐
Ccache was originally written by Andrew Tridgell and is currently developed and maintained by Joel Rosdahl. See AUTHORS.txt or AUTHORS.html and https://ccache.dev/credits.html for a list of contributors. Legends, all of them. ๐ซก
And that's a wrap on the whole page, bestie!! ๐ This was Ccache 4.14.1, dated 2026-10-04 โ go forth and have a slay build, mwah ๐โจ๐ฆ
๐ฆ where this page comes from
- arch rolling: ccache 4.14.1-1 ยท GPL-3.0-or-later
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms