Inconvenience caused by packages calling 'cmake_minimum_required()' when using `find_package()`?

I tried looking around for discussion related to this topic and was surprised to find none, so I figured I’d post this here.

So my initial confusion was caused because I have a script like this:

cmake_minimum_required(VERSION 3.21.1)
...
find_package(Qt6)
...
message(STATUS ${CMAKE_MINIMUM_REQUIRED_VERSION})

Where that last statement would print “3.16”. It took a bit to narrow down the highlighted find_package call, but in the end that is for sure the culprit.

The documentation for CMAKE_MINIMUM_REQUIRED_VERSION says:

The <min> version of CMake given to the most recent call to the cmake_minimum_required(VERSION) command in the current variable scope or any parent variable scope.

Since find_package() doesn’t create its own scope, everything here is ‘sound’ and working as intended… but, from a practical standpoint I don’t really find that this makes sense, or at least it doesn’t seem useful.

I feel like intuitively you’d ether want CMAKE_MINIMUM_REQUIRED_VERSION to contain the value from the top most call to cmake_minimum_required or what is in reality the ACTUAL minimum version required for a project, that being the maximum version set amongst all calls to cmake_minimum_required.

Ignoring the CMake features used in your own scripts, if you load in three package dependencies and they respectively declare:

  • cmake_minimum_required(VERSION 3.12)
  • cmake_minimum_required(VERSION 3.23.1)
  • cmake_minimum_required(VERSION 3.0)

then the true minimum required version for this project as a whole would be 3.23.1, but at this point CMAKE_MINIMUM_REQUIRED_VERSION would contain 3.0.

At the very least, like I said I’d at least expect only the minimum version calls from my own scripts to affect that value. It makes me surprised that package Config files aren’t loaded in their own scope, with the variables they need to set just provided back via PARENT_SCOPE.

Or, better yet, that there isn’t a CMAKE_TOP_MINIMUM_REQUIRED_VERSION variable defined, similar to how there is CMAKE_BINARY_DIR / CMAKE_CURRENT_BINARY_DIR (and other flavors of such).

Sure, in the end, I can just declare my own variable early on before any find_package calls and use that wherever I need to substitute the minimum version that I set myself, but it just makes CMAKE_MINIMUM_REQUIRED_VERSION seem like a not very useful variable when you essentially can’t trust its contents to be straightforward.

I just wanted to see what others thought about this situation and if this is something that was ever addressed by Kitware

1 Like

It is something I’ve wanted too, but it hasn’t been that way “forever” and fixing it now is…daunting.

That sounds like a bug in the Qt6 package to me. Package scripts should not be using cmake_minimum_required but instead cmake_policy(PUSH) and cmake_policy(POP) to make a policy scope and set the policies necessary. If some other minimum is needed, just check it and error with a meaningful message.

I can’t say I’ve ever wanted to use the variable…I just document minimum required versions, error if it’s an API, and use the features I’m allowed to use under those constraints.

1 Like

Yea, I understand that with CMake’s intense commitment to backwards compatibility, something as seemingly innocuous as this is actually a huge deal.

Ok, I actually was wondering if this is something Qt shouldn’t be doing, so for this particular case I’ll discuss that with them. Thanks for pointing out the more “standard way”.

This I can understand, and is certainly the better way to handle things, but I’m still on my first CMake project and it isn’t flexible enough to be setup in a way where it can function differently given different CMake version cut-offs. Particularly so in this case because it’s a static lib based on Qt (big surprise) and static builds of Qt6 require 3.21.1, while my scripts don’t actually need anything that recent, so its basically just >= 3.21.1 or bust.

So for now at least its straightforward for me to forward the minimum version I set in the project definition to my Doxygen run and call it a day.

I’d just focus on getting things to work on any CMake version to start. Once you have that working, you can experiment with supporting older CMake versions too, but it’s usually just easier to require newer CMake versions unless you actually have use cases (read: users) that only have an older CMake around.

1 Like