FetchContent: why re-pulling unchanged child project under Gitlab CI?

Synopsis: On standalone workstation, child project is not re-pulled by FetchContent unless it changes, whereas under Gitlab CI it is re-pulled every pipeline run, even if unchanged.

I have two projects, Parent and Child, each living in separate Git repos, and each built with a CMakeLists.txt (‘CML’). Child is a library, a dependency of many other projects including this Parent. Child is declared a dependency in Parent’s CML using FetchContent, pointing to GIT_REPOSITORY url (a cmake cache variable) and referencing an SHA1 commit as GIT_TAG.

Parent and Child both build successfully on standalone workstation using CMake 3.16. By ‘success’ I also mean that changes to Child’s GIT_TAG imply that re-building the Parent will trigger rebuild of Child. And for unchanged Child GIT_TAG but changes to Parent, Parent re-builds will not trigger re-builds nor re-pulls of Child.

I’m replicating my setups under Gitlab in CI pipeline, each for Parent and Child. The CI build stage invokes (cmake 3.28) cmake -G… and cmake --build…, just as in standalone workstation. The pipeline in each case caches the build and install directories for incremental re-use. FetchContent (ExternalProject) works fine pulling into the pipeline from Gitlab repository.

All works fine EXCEPT that for the pipeline which builds Parent, the Child is repeatedly re-built, even though its referenced GIT_TAG (SHA1) remains unchanged.

Attempting diagnosis, even though (I believe) file timestamps shouldn’t matter, since the Child’s GIT_TAG is an SHA1, I see upon re-running the CI pipeline, that the cached/retrieved build folder timestamps have not been otherwise altered, but…:

  1. The unchanged Parent’s source files pulled in from Gitlab repo have timestamps of the repo’s creation on Gitlab.
  2. the Parent’s object file (.o) timestamps (in the cached/retrieved build folder) remain fixed to its first/recent build, and its source is not repeatedly re-built, which is correct behavior.
  3. The Child’s source and object file timestamps show the time of the most recent Parent pipeline run, indicating the Child is being re-Fetched/cloned/checked-out each time. This is confirmed by unquieting the FetchContent_Quiet flag.
  4. If I build the Child as top-level project (its own separate pipeline), it behaves like the Parent above: its source timestamps reflect its repo creation on Gitlab.

Can anyone suggest what/why is happening and/or any diagnostic ideas?

Dang, found the cause: each pipeline run re-invokes cmake -G… with the existing build folder cache, if I comment-out that invocation in pipeline script, the correct behavior ensues.

But I thought cmake -G… on an existing build directory would incrementally update things, as evidenced by the undisturbed Parent object files in my previous pipeline runs.

Explanations on cmake -G impact on this issue?

That doesn’t sound right, but the setup sounds complicated. It may be in the details of how you’ve constructed things and exactly the commands used. Not sure if that’s getting beyond what folks might be willing to crawl through here to help you though.