# How to determine chosen CMake version (or existence of specific feature)?

**URL:** https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489
**Category:** Usage
**Created:** [April 19, 2022, 3:32pm UTC](https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489 "2022-04-19T15:32:05Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![dbahadir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dbahadir/32/197_2.png) [@dbahadir](https://discourse.cmake.org/u/dbahadir)
#### Post date: [April 19, 2022, 3:32pm UTC](https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489/1 "2022-04-19T15:32:05Z")

</div>

**tl;dr** Is there any way to determine the existence of a CMake feature if it does not have a policy?

I am trying to extend my CMake project with (optional) support for the new `FILE_SET` feature introduced with CMake 3.23.

I thought I could just check for `CMAKE_VERSION` to determine if the `FILE_SET` feature is available and then use it. And in general it works, as `CMAKE_VERSION` gives me back the version of the `cmake` executable:

```cmake
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.23")
    target_sources( my_target PUBLIC FILE_SET ... )
else()
    target_sources( my_target PUBLIC ... )
endif()

```

However, I noticed even if I am using `cmake_minimum_required( VERSION 3.20...3.22 )`, which pretty much says that my code is not supposed to know and therefore not use the `FILE_SET` feature, the value of `CMAKE_VERSION` still shows the real version of the `cmake` executable and therefore the first branch from the above `if` would be chosen. (Assume above code snippet comes from some 3rd-party CMake module into my CMake code.)

As my implementation was not entirely done - I was still using `install( TARGETS ... )` without installing the `FILE_SET` - I thought I could prevent choosing this half-implemented execution path by using the above `if`.  
However, it obviously does not work this way and CMake gives me an error “`install TARGETS target my_target is exported but not all of its file sets are installed`”.

So, is it somehow possibly to honor the chosen CMake (compatibility) version and not use a feature that comes from a later CMake version (even if using an up-to-date `cmake` executable)?  
(Maybe I am just blind and overlooked the correct CMake variable but I was unable to find it.)

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [April 19, 2022, 4:34pm UTC](https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489/2 "2022-04-19T16:34:56Z")

</div>

> [@dbahadir](#):
>
> So, is it somehow possibly to honor the chosen CMake (compatibility) version and not use a feature that comes from a later CMake version

No, the only way to make sure is to actually use and test the minimum CMake version.

> [@dbahadir](#):
>
> Is there any way to determine the existence of a CMake feature if it does not have a policy?

The version check is the way to do this.

> [@dbahadir](#):
>
> which pretty much says that my code is not supposed to know and therefore not use the `FILE_SET` feature

Eh. It more says that “this project requires 3.20 to work at all, but it knows about 3.22 and is OK with policies added to that point”. Conditionals to do other things if better replacements are available are still possible.

Think of it this way: if CMake locked its features behind minimum CMake declarations, then CMake’s own modules would “never” be able to use new features. Instead, they use the new features (and set the policies to NEW where needed for such things for itself).

---

<div class="post-metadata">

### Author: ![dbahadir](https://discourse.cmake.org/user_avatar/discourse.cmake.org/dbahadir/32/197_2.png) [@dbahadir](https://discourse.cmake.org/u/dbahadir)
#### Post date: [April 20, 2022, 9:52am UTC](https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489/3 "2022-04-20T09:52:57Z")

</div>

> [@ben.boeckel](#):
>
> > [@dbahadir](#):
> >
> > which pretty much says that my code is not supposed to know and therefore not use the `FILE_SET` feature
> 
> Eh. It more says that “this project requires 3.20 to work at all, but it knows about 3.22 and is OK with policies added to that point”. Conditionals to do other things if better replacements are available are still possible.
> 
> Think of it this way: if CMake locked its features behind minimum CMake declarations, then CMake’s own modules would “never” be able to use new features. Instead, they use the new features (and set the policies to NEW where needed for such things for itself).

So, for `cmake_minumum_required( VERSION min...max )` there is no way to determine `max` (especially if `CMAKE_VERSION` is newer than `max`)!?

That is pretty sad. Because it prevents the following use-case (I was trying to explain above):

Assume that from some 3rd-party CMake module you get some functionality which conditionally uses a newer CMake feature if the used `cmake` version is new enough, e.g. it uses `target_sources( my_target ... FILE_SET ... )` if the `cmake` version is at least 3.23.  
If I then use that 3rd-party CMake module in my CMake code and there I just do a simple `install( TARGETS my_target ... )` ignoring (or not knowing about) the special `FILE_SET` feature (especially because it uses `cmake_minimum_required( VERSION 3.20...3.22 )`) the code will work as long as my users use a `cmake` executable which is not newer than 3.22.x. However, as soon as the `cmake` executable is updated to `3.23` or newer, the code will suddenly break (with “`install TARGETS target my_target is exported but not all of its file sets are installed`”).

* * *

Further, this behavior is grist to the mill of people that want to stick with ancient CMake versions.

I was always advising people (also in my CMake conference talks) to update to more recent CMake versions because CMake is great with backwards-compatibility (due to `cmake_minimum_required`) and they thereby get problems fixed (and because it is simple/cheap to update CMake).  
However, I might have to reconsider this advice, as problems as the one described above could arise.

**I really think this is a viable problem which could easily be fixed if one could check what the maximal chosen CMake version is.**

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [April 20, 2022, 10:32am UTC](https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489/4 "2022-04-20T10:32:18Z")

</div>

> [@dbahadir](#):
>
> I really think this is a viable problem which could easily be fixed if one could check what the maximal chosen CMake version is.

There is no “maximal chosen CMake version” though. There is “newest version the code is aware of”, but that is not a cap on what CMake is allowed because CMake continues working with older code as much as is possible.

> [@dbahadir](#):
>
> Assume that from some 3rd-party CMake module you get some functionality which conditionally uses a newer CMake feature if the used `cmake` version is new enough, e.g. it uses `target_sources( my_target ... FILE_SET ... )` if the `cmake` version is at least 3.23.

I would expect it to have some documentation to this effect. Ideally, there would be some way to tell it “please don’t use the new behavior”. If the API wrapped the source listing _and_ installation, it could do this, but since it appears that it does not, `FILE_SET` will likely need to be an opt-in mechanism on the caller side.

> [@dbahadir](#):
>
> I was always advising people (also in my CMake conference talks) to update to more recent CMake versions because CMake is great with backwards-compatibility (due to `cmake_minimum_required`) and they thereby get problems fixed (and because it is simple/cheap to update CMake).

CMake has great backwards compatibility (old code works with new CMake releases). What it does _not_ guarantee is forward compatibility (new code is benign in old CMake releases). The recommendation is usually to use the minimum CMake version’s documentation when developing (or pay attention to the “available since” stanzas now available). The `...<max>` is just to say “I have adapted for the policy changes up to this version” not “I have started using all the new features available as of `...<max>`”; that needs some other mechanism.

As an example, a project may say `...3.17`, but this does _not_ mean that it guarantees working with the `Ninja Multi-Config` generator that was added in that version.

---

<div class="post-metadata">

### Author: ![martijntje](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/838e76/32.png) [@martijntje](https://discourse.cmake.org/u/martijntje)
#### Post date: [April 22, 2022, 11:05am UTC](https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489/5 "2022-04-22T11:05:31Z")

</div>

Can’t you determine the CMake version by running `${CMAKE_PROGRAM} --version` with `execute_process`?

---

<div class="post-metadata">

### Author: ![ben.boeckel](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/b/ea5d25/32.png) [@ben.boeckel](https://discourse.cmake.org/u/ben.boeckel)
#### Post date: [April 22, 2022, 12:03pm UTC](https://discourse.cmake.org/t/how-to-determine-chosen-cmake-version-or-existence-of-specific-feature/5489/6 "2022-04-22T12:03:50Z")

</div>

That doesn’t help at all. In CMake, you just use `CMAKE_VERSION`. What is not exposed right now is the `...<max>` part of a minimum version request.
