Feature Request: warning for conflicting FetchContent options

The documentation for FetchContent_Declare states

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 <name> are ignored. This “first to record, wins” approach is what allows hierarchical projects to have parent projects override content details of child projects.

I understand the rationale of allowing parent projects to override included projects. However, this can lead to issues if one of the child projects requires a different version of a dependency. Finding out why versions mismatch is a major headache and comes down to tracing back to which project first declared a target, once it’s clear that is the culprit.

We are making heavy use of FetchContent to pull in git repositories across multiple interdependent projects. Keeping them in sync is not a trivial task and we have run into issues where the requested git tags have diverged.

Could we have a flag for FetchContent that explicitly asks for a warning (or even error) if FetchContent options for a given dependency diverge? I’d rather have an early indication when running CMake than spend hours trying to figure out why some project down in the hierarchy stopped compiling.

Thanks
Joseph

As the maintainer of FetchContent, I’m not opposed to the feature in principle, but I’m unlikely to implement it myself. I question the value of what you’re asking for (not the problem you’re facing). I think you’ll find such a warning or error would trigger on too many false positives. The whole “first to declare, wins” principle is based around the expectation that overrides typically will be different.

Since it sounds like you’re in a company environment where you might be in control of all the projects involved, I’ll sketch out an alternative idea that has been bouncing around my head for a while. Instead of putting FetchContent_Declare() calls in each project, an alternative might be to have a separate repository which consists exclusively of FetchContent_Declare() calls covering all the different dependencies you might use across all your projects. Importantly, this separate repo would not call FetchContent_MakeAvailable() on any dependencies. Its sole job is to declare dependency details only. Then in each project, the first thing it does is bring in this separate repo (this would be the only time that project would need to call FetchContent_Declare() so it can bring in the separate “dependency repo”, followed by the FetchContent_MakeAvailable() call of course).

With the above arrangement, the top level repository still has full control over all dependencies. However, now you have one repository responsible for ensuring all dependencies are consistent. You can create branches in that dependency repository to experiment with different combinations of dependency versions, or to handle dependencies for releases, etc. An important part of this picture I haven’t yet worked through enough in my head though is what the workflow would look like for updating the hashes in projects when you want to move to a different set of dependencies. You’ll need to update the hashes in the dependency repo, then as you want a project to adopt the newer dependencies, you would update the one and only FetchContent_Declare() call in that project (the one that references the dependencies repo).

Sorry if that all sounds too wordy. It would be better to have diagrams, etc. to sketch this out. It’s been on my mind for a few years, but I’ve just never gotten around to fleshing out the details and trying it in anger on real projects.