# \`write\_basic\_package\_version\_file\` and version range

**URL:** <https://discourse.cmake.org/t/write-basic-package-version-file-and-version-range/10021>\
**Category:** Code\
**Created:** [February 7, 2024, 7:35am UTC](https://discourse.cmake.org/t/write-basic-package-version-file-and-version-range/10021 "2024-02-07T07:35:42Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)\
**Post date:** [February 7, 2024, 7:35am UTC](https://discourse.cmake.org/t/write-basic-package-version-file-and-version-range/10021/1 "2024-02-07T07:35:43Z")

</div>

From reading the templates used by `write_basic_package_version_file` it seems that the parent project has the ultimate say of how the `find_package` works, e.g. if `SameMajorVersion` is used, passing a range like `2.0...4.0` will always fail because only version ranges with the same major are supported.

But then the question is, if the consuming project has a special handling for those ranges so that all of them are supported, how should we design around the packaged project’s restrictions? My only guess is to design a `Find<Package>.cmake` wrapper where the version range is processed, setting the final `<Package>_FOUND` variable.

Edit: I’ve noticed a flaw with the `Find<Package>.cmake` approach. Let’s assume we are consuming via

```cmake
FetchContent_Declare(ProjectA
		GIT_REPOSITORY https://github.com/user/project-a
		GIT_TAG v2.3.0
		FIND_PACKAGE_ARGS MODULE
		)

```

With a `FindProjectA.cmake` file like:

```cmake
find_package(ProjectA CONFIG)
if (ProjectA_VERSION VERSION_LESS 2)
  set(ProjectA_FOUND FALSE)
elseif (ProjectA_VERISON VERSION_GREATER 3)
  message(WARNING "Support for ProjectA ${ProjectA_VERISON} is experimental. Please report to ...")
endif ()

```

The issue is that within the `FindProjectA.cmake`, the targets were already defined by `find_package(CONFIG)`, so when it goes through `FetchContent` path as the fallback, the target names can potentially clash.

---

<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:** [February 7, 2024, 8:45pm UTC](https://discourse.cmake.org/t/write-basic-package-version-file-and-version-range/10021/2 "2024-02-07T20:45:53Z")

</div>

I don’t know that the templates ever considered version ranges; I suspect that it is older than range support at all (@brad.king?).

As for conflicting targets, yes, that seems like a problem. However, I think it is more that dependency management needs to be a bit more uniform within a single CMake project rather than “handle all possible conflicts”. @craig.scott?

---

<div class="post-metadata">

**Author:** ![craig.scott](https://discourse.cmake.org/user_avatar/discourse.cmake.org/craig.scott/32/20_2.png) [@craig.scott](https://discourse.cmake.org/u/craig.scott)\
**Post date:** [February 24, 2024, 1:04am UTC](https://discourse.cmake.org/t/write-basic-package-version-file-and-version-range/10021/3 "2024-02-24T01:04:04Z")

</div>

> [@ben.boeckel](#):
>
> I don’t know that the templates ever considered version ranges; I suspect that it is older than range support at all (@brad.king?).

The current implementation of `write_basic_package_version_file()` pre-dates version ranges. It provides some common version strategies, with `SameMajorVersion` essentially corresponding to semantic versioning. The use case discussed here is not semantic versioning, so `SameMajorVersion` isn’t appropriate. But if the package’s project does follow semantic versioning, then consumers must abide by that and can’t simply assume some other versioning logic when calling `find_package()`. The alternative would be to leave out any version specification from the `find_package()` call, and implement something like the `VALIDATOR` support for `find_package()`. At the moment, `VALIDATOR` is only supported for `find_file()`, `find_path()`, `find_library()`, and `find_program()`. CC: @marc.chevrier

> [@ben.boeckel](#):
>
> As for conflicting targets, yes, that seems like a problem. However, I think it is more that dependency management needs to be a bit more uniform within a single CMake project rather than “handle all possible conflicts”. @craig.scott?

A well-behaved config package file will only create targets if the `find_package()` call will succeed. This recommendation is frequently violated though. If a config package file creates targets but the `find_package()` call doesn’t deem the package to be found, that’s a bug in the config package file logic, not something that we should try to support workarounds for in CMake.

To be clear, projects should never explicitly set `<packageName>_FOUND` themselves. Those variables should be set only as part of calls to `find_package()`. Projects that try to clear or modify such variables are broken, in my view.

---

<div class="post-metadata">

**Author:** ![Lecris](https://discourse.cmake.org/user_avatar/discourse.cmake.org/lecris/32/3193_2.png) [@Lecris](https://discourse.cmake.org/u/Lecris)\
**Post date:** [February 24, 2024, 5:20am UTC](https://discourse.cmake.org/t/write-basic-package-version-file-and-version-range/10021/4 "2024-02-24T05:20:37Z")

</div>

> [@craig.scott](#):
>
> The alternative would be to leave out any version specification from the `find_package()` call, and implement something like the `VALIDATOR` support for `find_package()`.

That sounds good, but what would be passed to it? Seems like only project version is doable before a target is defined? It would be nice if there was a dry run variant of find\_package that would only collect the tatget names (and maybe properties)

> [@craig.scott](#):
>
> A well-behaved config package file will only create targets if the `find_package()` call will succeed. This recommendation is frequently violated though. If a config package file creates targets but the `find_package()` call doesn’t deem the package to be found, that’s a bug in the config package file logic, not something that we should try to support workarounds for in CMake.
> 
> To be clear, projects should never explicitly set `<packageName>_FOUND` themselves. Those variables should be set only as part of calls to `find_package()`. Projects that try to clear or modify such variables are broken, in my view.

The issue is if `find_package(CONFIG)` is called within a `Find<Package>.cmake`. In that case, even if the config package is well behaved, you might want to try again with other version constraints, or with pkg-config, etc.

---

<div class="post-metadata">

**Author:** ![marc.chevrier](https://discourse.cmake.org/letter_avatar_proxy/v4/letter/m/ecb155/32.png) [@marc.chevrier](https://discourse.cmake.org/u/marc.chevrier)\
**Post date:** [February 24, 2024, 4:27pm UTC](https://discourse.cmake.org/t/write-basic-package-version-file-and-version-range/10021/5 "2024-02-24T16:27:05Z")

</div>

`write_basic_package_version_file()` is able to generate a version file which is aware of versions range but in the context of the constraints specified (i.e. `AnyNewerVersion` or `SameMajorVersion` or `|SameMinorVersion`).

Now, for a more smart handling of versions range, the best approach is to update the package itself (i.e. Version.cmake file).

Adding a `VALIDATOR` argument can be an interesting enhancement for specific cases, but a deep evaluation must be done to take care of all possible implications…
