build: ccache doesn’t hit across build dirs #31994
issue fanquake openend this issue on March 5, 2025-
fanquake commented at 11:30 am on March 5, 2025: memberThis has regressed since 28.x. Opening an issue to track given #30861 has been closed. Tagged for 29.x because ideally this would be fixed, and any fix could be backported.
-
fanquake added this to the milestone 29.0 on Mar 5, 2025
-
hebasto commented at 1:04 pm on March 9, 2025: member
TL;DR
To enable ccache hits across different build directories on Linux or macOS, configure the ccache options as follows:
0base_dir = <path_to_your_home_directory> 1hash_dir = false
or via environment variables:
0$ export CCACHE_BASEDIR=$HOME 1$ export CCACHE_NOHASHDIR=1
Detailed Solution
All following commands were executed on Ubuntu 24.04.2 LTS with ccache 4.9.1 installed.
Consider building in two separate build directories with ccache debugging enabled:
0$ export CCACHE_DEBUG=1 1$ printenv | grep CCACHE 2CCACHE_DEBUG=1 3$ export CCACHE_DIR=$(mktemp -d) 4$ cmake -B build_first -DWITH_CCACHE=ON 5$ cmake --build build_first -t bitcoin_crypto -j $(nproc) 6$ cmake -B build_second -DWITH_CCACHE=ON 7$ ccache -z 8$ cmake --build build_second -t bitcoin_crypto -j $(nproc) 9$ ccache -s 10Cacheable calls: 20 / 20 (100.0%) 11 Hits: 0 / 20 ( 0.00%) 12 Direct: 0 13 Preprocessed: 0 14 Misses: 20 / 20 (100.0%) 15Local storage: 16 Cache size (GiB): 0.0 / 5.0 ( 0.09%) 17 Hits: 0 / 20 ( 0.00%) 18 Misses: 20 / 20 (100.0%)
There were 100% misses. A comparison of the combined input used for hashing for an object file provides some clues:
0$ diff -u build_first/src/crypto/CMakeFiles/bitcoin_crypto.dir/aes.cpp.o.*.ccache-input-text build_second/src/crypto/CMakeFiles/bitcoin_crypto.dir/aes.cpp.o.*.ccache-input-text 1--- build_first/src/crypto/CMakeFiles/bitcoin_crypto.dir/aes.cpp.o.20250309_113307_205745.ccache-input-text 2025-03-09 11:33:07.669373196 +0000 2+++ build_second/src/crypto/CMakeFiles/bitcoin_crypto.dir/aes.cpp.o.20250309_113435_261959.ccache-input-text 2025-03-09 11:34:35.664968636 +0000 3@@ -10,7 +10,7 @@ 4 ### LANG 5 en_US.UTF-8 6 ### cwd 7-/home/hebasto/dev/bitcoin/build_first 8+/home/hebasto/dev/bitcoin/build_second 9 === DIRECT MODE === 10 ### cache entry version 11 1 12@@ -83,7 +83,7 @@ 13 ### arg 14 -DENABLE_X86_SHANI 15 ### arg 16--I/home/hebasto/dev/bitcoin/build_first/src 17+-I/home/hebasto/dev/bitcoin/build_second/src 18 ### arg 19 -I/home/hebasto/dev/bitcoin/src 20 ### arg 21@@ -170,7 +170,7 @@ 22 /home/hebasto/dev/bitcoin/src/crypto/aes.cpp 23 " 24 # 1 " 25-/home/hebasto/dev/bitcoin/build_first 26+/home/hebasto/dev/bitcoin/build_second 27 " 28 # 0 " 29 <built-in>
Hence, we need to address:
- Absolute paths in compiler invocation commands, and
- Hashing of the current working directory.
The documented method to resolve the first issue is the
base_dir
ccache configuration option. The current recommendation from our Productivity Notes remains valid:base_dir
is required for ccache to share cached compiles of the same file across different … paths; it will only do this for paths underbase_dir
.Additionally, ccache docs state:
The CWD will not be included in the hash if
base_dir
is set (and matches the CWD) and the compiler option-fdebug-prefix-map
is used.The latter is always true:https://github.com/bitcoin/bitcoin/blob/4637cb1eec48d1af8d23eeae1bb4c6f8de55eed9/CMakeLists.txt#L473-L475
However, in CMake builds the CWD is a build directory. Therefore, none of the meaningful values of
base_dir
will trigger the skipping of CWD hashing. We must explicitly use thehash_dir
option to disable this behaviour.Now, let’s set
base_dir
and disablehash_dir
:0$ export CCACHE_BASEDIR=$HOME 1$ export CCACHE_NOHASHDIR=1 2$ export CCACHE_DIR=$(mktemp -d) 3$ cmake -B build_first -DWITH_CCACHE=ON 4$ cmake --build build_first -t bitcoin_crypto -j $(nproc) 5$ cmake -B build_second -DWITH_CCACHE=ON 6$ ccache -z 7$ cmake --build build_second -t bitcoin_crypto -j $(nproc) 8$ ccache -s 9Cacheable calls: 20 / 20 (100.0%) 10 Hits: 20 / 20 (100.0%) 11 Direct: 20 / 20 (100.0%) 12 Preprocessed: 0 / 20 ( 0.00%) 13 Misses: 0 / 20 ( 0.00%) 14Local storage: 15 Cache size (GiB): 0.0 / 5.0 ( 0.04%) 16 Hits: 20 / 20 (100.0%) 17 Misses: 0 / 20 ( 0.00%)
We’ve got 100% hits.
Ccache docs warn about disabling CWD hashing:
The reason for including the CWD in the hash by default is to prevent a problem with the storage of the current working directory in the debug info of an object file, which can lead ccache to return a cached object file that has the working directory in the debug info set incorrectly.
However, I do not see how this affects us, as all paths in the debug information of object files are mapped as mentioned above.
-
hebasto commented at 1:09 pm on March 9, 2025: memberAmending our docs, as demonstrated in https://github.com/davidgumberg/bitcoin/commit/1c6ae1043d59d01cbf52f353e50a63b0afa883c4, could be an alternative to #30861.
-
ryanofsky commented at 2:39 pm on March 11, 2025: contributor
Thanks for writing this up so clearly. It would be good to add this to the documentation.
re: #31994 (comment)
Additionally, ccache docs state:
The CWD will not be included in the hash if
base_dir
is set (and matches the CWD) and the compiler option-fdebug-prefix-map
is used.I still don’t understand why setting
hash_dir = false
orCCACHE_NOHASHDIR=1
should be necessary. Both conditions listed would seem to be true. Both CWD’s (/home/hebasto/dev/bitcoin/build_first and /home/hebasto/dev/bitcoin/build_second) should match the base_dir (/home/hebasto) because the according to the base_dir documentation it matches “absolute paths that begin with base_dir”.However, in CMake builds the CWD is a build directory. Therefore, none of the meaningful values of
base_dir
will trigger the skipping of CWD hashing. We must explicitly use thehash_dir
option to disable this behaviour.This doesn’t seem true. How do /home/hebasto/dev/bitcoin/build_first and /home/hebasto/dev/bitcoin/build_second not match /home/hebasto?
-
hebasto commented at 2:50 pm on March 11, 2025: member
Thanks for writing this up so clearly. It would be good to add this to the documentation.
re: #31994 (comment)
Additionally, ccache docs state:
The CWD will not be included in the hash if
base_dir
is set (and matches the CWD) and the compiler option-fdebug-prefix-map
is used.I still don’t understand why setting
hash_dir = false
orCCACHE_NOHASHDIR=1
should be necessary. Both conditions listed would seem to be true. Both CWD’s (/home/hebasto/dev/bitcoin/build_first and /home/hebasto/dev/bitcoin/build_second) should match the base_dir (/home/hebasto) because the according to the base_dir documentation it matches “absolute paths that begin with base_dir”.This interpretation of the Ccache documentation does not describe the actual behaviour on my different systems. I read “
base_dir
matches the CWD” as “base_dir
equals the CWD”. However, I might be wrong. -
ryanofsky commented at 3:21 pm on March 11, 2025: contributor
This interpretation of the Ccache documentation does not describe the actual behaviour on my different systems. I read “base_dir matches the CWD” as “base_dir equals the CWD”. However, I might be wrong.
You are probably right but this behavior does not seem to make sense or correspond to documentation of base_dir. It is probably ok for us to force CCACHE_NOHASHDIR, but it seems like it would be safer if ccache just detected conditions it should and shouldn’t hash CWD correctly itself. Ccache’s behavior here seems nonsensical.
-
hebasto commented at 4:49 pm on March 11, 2025: member
This interpretation of the Ccache documentation does not describe the actual behaviour on my different systems. I read “base_dir matches the CWD” as “base_dir equals the CWD”. However, I might be wrong.
You are probably right but this behavior does not seem to make sense or correspond to documentation of base_dir. It is probably ok for us to force CCACHE_NOHASHDIR, but it seems like it would be safer if ccache just detected conditions it should and shouldn’t hash CWD correctly itself. Ccache’s behavior here seems nonsensical.
It looks like this code is responsible for that behaviour:
0 if (inc_path != ctx.apparent_cwd || ctx.config.hash_dir()) { 1 hash.hash(inc_path); 2 }
-
willcl-ark added the label Build system on Mar 19, 2025
This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-03-31 09:12 UTC
More mirrored repositories can be found on mirror.b10c.me