Persisting fetch content files through a fresh configure

I use FetchContent to build dependency source code as part of my project, and as part of my CI pipeline (and sometimes locally) I do a fresh configure to ensure cmake cache variables from previous runs are cleared without needing to wipe the build directory and rebuild everything.

This works fine for my own project files, but as dependency source files are downloaded again after a fresh configure they get a new timestamp and force a rebuild unnecessarily. Is there any way to avoid this behaviour, so the dependency source files can persist across a fresh configure?

I found this MR https://gitlab.kitware.com/cmake/cmake/-/merge_requests/9589 which states

We still keep the download directory under its existing FETCHCONTENT_BASE_DIR location so that downloaded files can survive across a cmake --fresh and be re-used on the next download step if suitable.

which makes me think that’s how it should work, as well as the docs for CMP0168 which state

The directory used for downloads is not affected by cmake --fresh, so any previously downloaded files for the URL download method can still be reused.

So I tried using the URL method instead of GIT but it has the same behaviour. I’m aware I could use DOWNLOAD_EXTRACT_TIMESTAMP which somewhat alleviates the problem as the timestamps wouldn’t be updated, but that introduces the risk that the files may change and get an older timestamp (e.g. switching to another branch using an older dependency version) and not rebuild when required

I’m confident I could roll my own solution using file(DOWNLOAD…) and add_subdirectory but I feel like I’m missing (or misunderstanding) something here and hoping I won’t have to do that

The behavior you observe is expected. The download will be short-circuited because it will find the already-downloaded files, but then it gets reunpacked again. This is important, as it ensures that anything that might have modified the original files (intentionally or not) should be discarded and replaced by the original files again. It restores integrity to the downloaded contents.

The above behavior is not intended to avoid rebuilding the dependency. You should expect things to rebuild. The way I’d recommend minimising the build-time impact of that is to use a compiler cache like ccache. That should make rebuilds trivially fast in most cases. It can take a bit more to get a persistent cache set up for CI, but for larger projects, it’s worth it (few things in software are going to deliver the order-of-magnitude gains in build time that a compiler cache will typically give you).