Issue
I'm running cmake 3.23.0. I want to find_library(VTK) based on version criteria. My ubuntu 20.04 system has two installed versions of VTK:
/usr/local/lib/cmake/vtk-8.2
/usr/local/lib/cmake/vtk-9.0
My project requires VTK version 8.x.x, i.e. need to exclude VTK 9.x.x - so CMakeLists.txt includes:
find_package(VTK "8...<9" REQUIRED)
But VTK_VERSION found is 9.0.1 - why, given the constraint? Also tried
find_package(VTK "8.0...<9.0" REQUIRED)
find_package(VTK "8.0.0...<9.0.0" REQUIRED)
with the same result - VTK_VERSION 9.0.1 is found. Tried without a version range, but still find_package() returns VTK_VERSION 9.0.1:
find_package(VTK "8" REQUIRED)
find_package(VTK “8.2” REQUIRED)
find_package(VTK “8.2.0” REQUIRED)
The only thing that actually returns VTK_VERSION 8.2.0:
find_package(VTK “8.2.0” REQUIRED EXACT)
Is this behavior due to the fact that two VTK versions are installed on my system, and find_packages() assumes just one is installed?
*** UPDATE #2: Contents of version configuration files in /usr/local/lib/cmake/vtk-.:
/usr/local/lib/cmake/vtk-8.2/VTKConfigVersion.cmake:
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major version is the same as the current one.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "8.2.0")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("8.2.0" MATCHES "^([0-9]+)\\.")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
else()
set(CVF_VERSION_MAJOR "8.2.0")
endif()
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
/usr/local/lib/cmake/vtk-9.0/vtk-config-version.cmake:
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "9.0.1")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
# if the installed project requested no architecture check, don't perform the check
if("FALSE")
return()
endif()
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
return()
endif()
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
math(EXPR installedBits "8 * 8")
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
*** UPDATE #1: CMake output with --debug-find-pkg=VTK:
CMake Debug Log at CMakeLists.txt:212 (find_package):
find_package considered the following paths for VTK.cmake
/home/oreilly/projects/mb-system/MB-System/build-utils/FindVTK.cmake
/usr/local/share/cmake-3.23/Modules/FindVTK.cmake
The file was not found.
<PackageName>_ROOT CMake variable [CMAKE_FIND_USE_PACKAGE_ROOT_PATH].
none
CMAKE_PREFIX_PATH variable [CMAKE_FIND_USE_CMAKE_PATH].
none
CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH variables
[CMAKE_FIND_USE_CMAKE_PATH].
none
Env variable VTK_DIR [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].
none
CMAKE_PREFIX_PATH env variable [CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].
none
CMAKE_FRAMEWORK_PATH and CMAKE_APPBUNDLE_PATH env variables
[CMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATH].
none
Paths specified by the find_package HINTS option.
none
Standard system environment variables
[CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].
/home/oreilly/OpenSceneGraph/build
/home/oreilly/projects/mb-system/MB-System/build
/home/oreilly/projects/hotspot/onboard/smc-script
/home/oreilly/projects/hotspot/onboard/script
/home/oreilly/myUtilities
/home/oreilly/cxxtest-4.3
/home/oreilly/Qt/Tools/QtCreator
/home/oreilly/Qt/5.14.2/gcc_64
/home/oreilly/Android/Sdk/platform-tools
/home/oreilly/android-studio/tools
/home/oreilly/android-studio
/home/oreilly/idea
/home/oreilly
/home/oreilly/.local
/usr/local
/usr
/
/usr/games
/usr/local/games
/snap
/home/oreilly/anaconda2
CMake User Package Registry [CMAKE_FIND_USE_PACKAGE_REGISTRY].
none
CMake variables defined in the Platform file
[CMAKE_FIND_USE_CMAKE_SYSTEM_PATH].
/usr/X11R6
/usr/pkg
/opt
CMake System Package Registry
[CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY].
none
Paths specified by the find_package PATHS option.
none
find_package considered the following locations for the Config module:
/home/oreilly/OpenSceneGraph/build/VTKConfig.cmake
/home/oreilly/OpenSceneGraph/build/vtk-config.cmake
/home/oreilly/projects/mb-system/MB-System/build/VTKConfig.cmake
/home/oreilly/projects/mb-system/MB-System/build/vtk-config.cmake
/home/oreilly/projects/hotspot/onboard/smc-script/VTKConfig.cmake
/home/oreilly/projects/hotspot/onboard/smc-script/vtk-config.cmake
/home/oreilly/projects/hotspot/onboard/script/VTKConfig.cmake
/home/oreilly/projects/hotspot/onboard/script/vtk-config.cmake
/home/oreilly/myUtilities/VTKConfig.cmake
/home/oreilly/myUtilities/vtk-config.cmake
/home/oreilly/cxxtest-4.3/VTKConfig.cmake
/home/oreilly/cxxtest-4.3/vtk-config.cmake
/home/oreilly/Qt/Tools/QtCreator/VTKConfig.cmake
/home/oreilly/Qt/Tools/QtCreator/vtk-config.cmake
/home/oreilly/Qt/5.14.2/gcc_64/VTKConfig.cmake
/home/oreilly/Qt/5.14.2/gcc_64/vtk-config.cmake
/home/oreilly/Android/Sdk/platform-tools/VTKConfig.cmake
/home/oreilly/Android/Sdk/platform-tools/vtk-config.cmake
/home/oreilly/android-studio/tools/VTKConfig.cmake
/home/oreilly/android-studio/tools/vtk-config.cmake
/home/oreilly/android-studio/VTKConfig.cmake
/home/oreilly/android-studio/vtk-config.cmake
/home/oreilly/idea/VTKConfig.cmake
/home/oreilly/idea/vtk-config.cmake
/home/oreilly/VTKConfig.cmake
/home/oreilly/vtk-config.cmake
/home/oreilly/CMake/VTKConfig.cmake
/home/oreilly/CMake/vtk-config.cmake
/home/oreilly/vtk/VTKConfig.cmake
/home/oreilly/vtk/vtk-config.cmake
/home/oreilly/VTK-8.2.0/VTKConfig.cmake
/home/oreilly/VTK-8.2.0/vtk-config.cmake
/home/oreilly/VTKWikiExamples-master/VTKConfig.cmake
/home/oreilly/VTKWikiExamples-master/vtk-config.cmake
/home/oreilly/VTK-9.0.1/VTKConfig.cmake
/home/oreilly/VTK-9.0.1/vtk-config.cmake
/home/oreilly/VTKExamples/VTKConfig.cmake
/home/oreilly/VTKExamples/vtk-config.cmake
/home/oreilly/vtk/CMake/VTKConfig.cmake
/home/oreilly/vtk/CMake/vtk-config.cmake
/home/oreilly/VTK-8.2.0/CMake/VTKConfig.cmake
/home/oreilly/VTK-8.2.0/CMake/vtk-config.cmake
/home/oreilly/VTKWikiExamples-master/CMake/VTKConfig.cmake
/home/oreilly/VTKWikiExamples-master/CMake/vtk-config.cmake
/home/oreilly/VTK-9.0.1/CMake/VTKConfig.cmake
/home/oreilly/VTK-9.0.1/CMake/vtk-config.cmake
/home/oreilly/VTKExamples/CMake/VTKConfig.cmake
/home/oreilly/VTKExamples/CMake/vtk-config.cmake
/home/oreilly/.local/VTKConfig.cmake
/home/oreilly/.local/vtk-config.cmake
/usr/local/VTKConfig.cmake
/usr/local/vtk-config.cmake
/usr/local/lib/cmake/vtk-9.0/VTKConfig.cmake
/usr/local/lib/cmake/vtk-9.0/vtk-config.cmake
The file was found at
/usr/local/lib/cmake/vtk-9.0/vtk-config.cmake
CMake Debug Log at CMakeLists.txt:212 (find_package):
Found VTK package version 9.0.1, VTK_LIBRARIES: VTK::WrappingTools;VTK::ViewsQt;[et cetera...]
Solution
find_package
picks the first package it finds according to the search procedure. When breaking ties in that search procedure, it goes in file system order. This depends on your file system, so it's unspecified.
For version selection it asks the package's *-config-version.cmake
or *ConfigVersion.cmake
script whether or not the package is compatible with the requested version. Packages that do not have such a script are assumed to be incompatible. Old packages will typically not understand version ranges and will tend to treat expressions like 8.0.0...<9.0.0
as simply 8.0.0
.
What you're seeing from the --debug-find-pkg=VTK
output is that your filesystem orders VTK 9 before VTK 8. Maybe that's because it's newer or happened to be assigned a smaller inode, or who knows? It's not guaranteed to be alphabetical or anything.
Then it considers VTK 9 first and loads the vtk-9.0/vtk-config-version.cmake
file. As you can see here:
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
it only checks if the current version (9.0.1) is less than the requested version (any of your version strings starting with 8
). Since 9 is not less than 8, the PACKAGE_VERSION_COMPATIBLE
variable is set to true and the package gets accepted.
When you specify EXACT
, that STREQUAL
comparison will return false and so PACKAGE_VERSION_EXACT
does not get set to TRUE
and so the package is rejected and the VTK 8 package is considered.
This is unfortunate behavior on the part of VTK 9. It's not sophisticated enough to interpret the version range arguments and it claims backwards compatibility with all previous versions.
To force VTK 8 to be used in your case, you should write the following:
find_package(VTK 8...<9 REQUIRED)
if (VTK_VERSION VERSION_GREATER_EQUAL 9)
message(FATAL_ERROR "This application requires VTK 8.x, but VTK ${VTK_VERSION} was found. Please set VTK_DIR to a folder containing the VTKConfig.cmake file from a VTK 8 installation.")
endif ()
Then you can set -DVTK_DIR=/usr/local/lib/cmake/vtk-8.2
at the command line.
Answered By - Alex Reinking Answer Checked By - Robin (WPSolving Admin)