Why is a FetchContent using a different TAG than the one I specified? How can I resolve this?

595 Views Asked by At

I am trying to use a certain library with FetchContent:

FetchContent_Declare(
    Catch2
    GIT_REPOSITORY https://github.com/catchorg/Catch2.git
    GIT_TAG        3f0283de7a9c43200033da996ff9093be3ac84dc
    GIT_PROGRESS   TRUE
    GIT_SHALLOW    FALSE
)
FetchContent_MakeAvailable(Catch2)

According to practice I am specifying a particular tag. However when I look at the files that cmake downloads, the tag is 7cf2f88e50f0d1de324489c31db0314188423b6d instead, and it is older (Feb 14 2023).

If I manually got to _deps/catch2-src and do git checkout 3f0283de7a9c43200033da996ff9093be3ac84dc, I get the correct version (Jun 21 2023).

What is wrong with the FetchContent block above? Why would CMake download the incorrect or older version of the library?

2

There are 2 best solutions below

3
On BEST ANSWER

My top suspect is

The FetchContent_Declare() function records the options that describe how to populate the specified content. If such details have already been recorded earlier in this project (regardless of where in the project hierarchy), this and all later calls for the same content are ignored.

2
On

From the FetchContent docs:

The FetchContent_Declare() function records the options that describe how to populate the specified content. If such details have already been recorded earlier in this project (regardless of where in the project hierarchy), this and all later calls for the same content are ignored.

If a previous call to FetchContent_Declare for the same name (in this case Catch2) chose a different TAG, the first one of those calls that sets TAG will "win". Are there any other calls to FetchContent_Declare for Catch2 anywhere in the configuration? Perhaps in one of your dependencies (if you have any)? If you don't want to search manually, you can use cmake --trace and then grep or jq for FetchContent_Declare calls.

This whole business is by design. From the same docs:

Projects should aim to declare the details of all dependencies they might use before they call FetchContent_MakeAvailable() for any of them. This ensures that if any of the dependencies are also sub-dependencies of one or more of the others, the main project still controls the details that will be used (because it will declare them first before the dependencies get a chance to)

Once you find the thing that's taking precendence, just move things around in your CMakeLists.txt so that your call to FetchContent_Declare goes first so it "wins".

If your call to FetchContent_Declare for a given name is the only one for that name, then you shouldn't have this problem. Even if you change the commitish being referenced in the TAG argument of your call, the next time your run configuration, CMake will update the checkout to that new commitish. And if you run build without reconfiguring, CMake is usually smart enough at knowing when it needs to reconfigure to do it automatically.