CMake: How to implement version check in a config file? - cmake

I Customize CMake package configure file OpenCLConfig.cmake for opencl-icd.
refer to Create CMake XXConfig.cmake let other cmake project invoke
Now, I encounter a problem: How to implement version check in a config file.
I create OpenCLConfigVersion.cmake beside OpenCLConfig.cmake, which content is:
#OpenCLConfigVersion.cmake
set(OpenCL_VERSION 2.2)
set(OpenCL_VERSION_MAJOR 2)
set(OpenCL_VERSION_MINOR 2)
SET(OpenCV_VERSION_PATCH 0)
SET(OpenCV_VERSION_TWEAK 0)
While I invoke it opencl-icd in others CMakeLists.txt,
that is find_package(OpenCL config)
I got this error:
CMake Error at CMakeLists.txt:10 (find_package): Could not find a
configuration file for package "OpenCL" that is compatible with requested
version "2". The following configuration files were considered but not
accepted: C:/SDKs/ocl-icd/OpenCLConfig.cmake, version: unknown
I have set OpenCL_DIR as "C:/SDKs/ocl-icd" in my CMakeLists.txt.
My customized OpenCLConfig.cmake which content is
set(OpenCL_FOUND TRUE)
set(OpenCL_ROOT_DIR "C:/SDKs/ocl-icd")
set(OpenCL_VERSION 2.2)
set(OpenCL_VERSION_MAJOR 2)
set(OpenCL_VERSION_MINOR 2)
SET(OpenCV_VERSION_PATCH 0)
SET(OpenCV_VERSION_TWEAK 0)
find_path(OpenCL_INCLUDE_DIR NAMES CL/cl.h PATHS "${OpenCL_ROOT_DIR}/include")
set(OpenCL_INCLUDE_DIRS "${OpenCL_INCLUDE_DIR}")
find_library(OpenCL_LIBRARY NAMES OpenCL.lib PATHS "${OpenCL_ROOT_DIR}/lib")
set(OpenCL_LIBRARIES ${OpenCL_LIBRARY})
How do I handle version problem.

I have solved.
I refer to OpenCVConfig-version.cmake write my OpenCLConfigVersion.cmake
#OpenCLConfigVersion.cmake
set(OpenCL_VERSION 2.2)
set(PACKAGE_VERSION ${OpenCL_VERSION})
set(PACKAGE_VERSION_EXACT False)
set(PACKAGE_VERSION_COMPATIBLE False)
if(PACKAGE_FIND_VERSION VERSION_EQUAL PACKAGE_VERSION)
set(PACKAGE_VERSION_EXACT True)
set(PACKAGE_VERSION_COMPATIBLE True)
endif()
if(PACKAGE_FIND_VERSION_MAJOR EQUAL 2
AND PACKAGE_FIND_VERSION VERSION_LESS PACKAGE_VERSION)
set(PACKAGE_VERSION_COMPATIBLE True)
endif()
It work normally after modify.

Related

cmake find_package(X [version]) always selects highest version of X if multiple versions installed?

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...]
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.

With CMake's find_package, why does version range 0.3.3...<0.5.0 not accept 0.4.6?

I want my repo to depend on a package with a certain allowed version range. So, looking at the documentation, I write:
find_package(mypkg 0.3.3...<0.5.0 REQUIRED)
but when I configure with CMake (v3.23.0-rc2), this line yields:
CMake Error at CMakeLists.txt:24 (find_package):
Could not find a configuration file for package "mypkg" that is
compatible with requested version range "0.3.3...<0.5.0".
The following configuration files were considered but not accepted:
/opt/mypkg/lib64/cmake/mypkg/mypkg-config.cmake, version: 0.4.6
Why is 0.4.6 not compatible with 0.3.3...<0.5.0 ? Or - is something else wrong?
Additional information:
The using repo's CMakeLists.txt has:
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
... changing it to 3.19 doesn't help.
By popular request, here's the package's auto-generated version config file:
# 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 and minor versions are the same as the current
# one.
# The variable CVF_VERSION must be set before calling configure_file().
set(PACKAGE_VERSION "0.4.6")
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
if("0.4.6" MATCHES "^([0-9]+)\\.([0-9]+)")
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
set(CVF_VERSION_MINOR "${CMAKE_MATCH_2}")
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
endif()
if(NOT CVF_VERSION_MINOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" CVF_VERSION_MINOR "${CVF_VERSION_MINOR}")
endif()
else()
set(CVF_VERSION_MAJOR "0.4.6")
set(CVF_VERSION_MINOR "")
endif()
if(PACKAGE_FIND_VERSION_RANGE)
# both endpoints of the range must have the expected major and minor versions
math (EXPR CVF_VERSION_MINOR_NEXT "${CVF_VERSION_MINOR} + 1")
if (NOT (PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
AND PACKAGE_FIND_VERSION_MIN_MINOR STREQUAL CVF_VERSION_MINOR)
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE"
AND NOT (PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR
AND PACKAGE_FIND_VERSION_MAX_MINOR STREQUAL CVF_VERSION_MINOR))
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE"
AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL ${CVF_VERSION_MAJOR}.${CVF_VERSION_MINOR_NEXT})))
set(PACKAGE_VERSION_COMPATIBLE FALSE)
elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
AND PACKAGE_FIND_VERSION_MIN_MINOR STREQUAL CVF_VERSION_MINOR
AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
set(PACKAGE_VERSION_COMPATIBLE TRUE)
else()
set(PACKAGE_VERSION_COMPATIBLE FALSE)
endif()
else()
if(NOT PACKAGE_FIND_VERSION_MAJOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" PACKAGE_FIND_VERSION_MAJOR "${PACKAGE_FIND_VERSION_MAJOR}")
endif()
if(NOT PACKAGE_FIND_VERSION_MINOR VERSION_EQUAL 0)
string(REGEX REPLACE "^0+" "" PACKAGE_FIND_VERSION_MINOR "${PACKAGE_FIND_VERSION_MINOR}")
endif()
if((PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR) AND
(PACKAGE_FIND_VERSION_MINOR STREQUAL CVF_VERSION_MINOR))
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()
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()
In short: The version range 0.3.3...<0.5.0 is incorrect from the view of the compatibility policy, specified for the package. Given package is treated as compatible only when both major and minor versions in the request are the same as the package's version.
Correct version requests could be:
0.3.3...<0.4.0
0.4.3...<0.5.0
(But the package with version 0.4.6 would satisfy only the second request).
Details
The config file is generated by write_basic_package_version_file with the COMPATIBILITY option SameMinorVersion. This can be deduced from the description:
# ... it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
# but only if the requested major and minor versions are the same as the current
# one.
If requested a version range with both ends included (without <), then both ends should have same major and minor versions:
# both endpoints of the range must have the expected major and minor versions
When upper end is excluded (with <), then it could have minor version greater by 1 than the lower end.
Allowed:
3.3.0...3.3.5
3.4.2...3.4.10
3.3.0...<3.3.5
3.3.2...<3.4
Disallowed:
3.3.0...3.4.0
3.3.0...4.3.0
3.3.0...<3.5
3.3.0...<3.4.1
Only when version range is allowed, the package's version is checked to be inside the range. In other cases the package is treated as incompatible with the request.
From my understanding, the version request semantic in find_package call is:
In case of single version requested, the package version should be compatible with requested version. And the package version should be no less than the requested one.
In case of version range without <, the package's version should be compatible with both ends. And the package version should belong to the range.
In case of version range with <, the upper end could denote the "next incompatible" version of the package. In other aspects this case is similar to one without <.

cmake cross-compile for raspberry pi

I am cross-compiling a library (ORBSLAM3) on pc using /usr and /lib
from rpi4 (After using rsync). And I put them in a folder named "rootf".The prerequisite libraries have been installed before so they are now in ~/rootf/usr and ~/rootf/lib. I need to compile ORBSLAM3 using ~/rootf/ as the root.
The thing is I am not familiar with cmake so I have been struggling for a while.
The process of compiling is this:
using Toolchain-rpi.cmake for the CMakeLists.txt on the top level of ORBSLAM3.
In CMakeLists.txt, it finds pangolin by find_package(Pangolin REQUIRED)
find_package() is actually doing the right.
It successfully finds
/home/ethan/raspberrypi/rootfs/usr/local/lib/cmake/Pangolin/PangolinTargets.cmake
The CMAKE_PREFIX_PATH in this CMakeLists.txt is right, which is
/home/ethan/raspberrypi/rootfs/usr/local/lib;/home/ethan/raspberrypi/rootfs/usr/lib/arm-linux-gnueabihf
After I uninstall pangolin on ubuntu, I get this:
CMake Error at /home/ethan/raspberrypi/rootfs/usr/local/lib/cmake/Pangolin/PangolinTargets.cmake:80 (message):
The imported target "pangolin" references the file
"/usr/local/lib/libpangolin.so"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
Since Pangolin was originally installed on board, so on board libpangolin.so is at /usr/local/lib/libpangolin.so.
I guess when I use PangolinTargets.cmake, it is doing the same thing.
I output CMAKE_SYSROOT,CMAKE_PREFIX_PATH,_IMPORT_PREFIX in PangolinTargets.cmake. It's what I expect.
CMAKE_SYSROOT = /home/ethan/raspberrypi/rootfs
CMAKE_PREFIX_PATH = ;/home/ethan/raspberrypi/rootfs/usr/local/lib;/home/ethan/raspberrypi/rootfs/usr/lib/arm-linux-gnueabihf
_IMPORT_PREFIX = /home/ethan/raspberrypi/rootfs/usr/local
Even if I add /home/ethan/raspberrypi/rootfs as prefix to the below paths, nothing changed.
set_target_properties(pangolin PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3;${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "rt;pthread;/usr/lib/arm-linux-gnueabihf/libGL.so;/usr/lib/arm-linux-gnueabihf/libGLU.so;
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3"
)
Here is the content of PangolinTargets.cmake. I am not sure which parts leads to searching only /usr. Thanks all.
# Generated by CMake
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
message(FATAL_ERROR "CMake >= 2.6.0 required")
endif()
cmake_policy(PUSH)
cmake_policy(VERSION 2.6)
#----------------------------------------------------------------
# Generated CMake target import file.
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
set(_targetsDefined)
set(_targetsNotDefined)
set(_expectedTargets)
foreach(_expectedTarget pangolin)
list(APPEND _expectedTargets ${_expectedTarget})
if(NOT TARGET ${_expectedTarget})
list(APPEND _targetsNotDefined ${_expectedTarget})
endif()
if(TARGET ${_expectedTarget})
list(APPEND _targetsDefined ${_expectedTarget})
endif()
endforeach()
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
return()
endif()
if(NOT "${_targetsDefined}" STREQUAL "")
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
endif()
unset(_targetsDefined)
unset(_targetsNotDefined)
unset(_expectedTargets)
# Compute the installation prefix relative to this file.
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
if(_IMPORT_PREFIX STREQUAL "/")
set(_IMPORT_PREFIX "")
endif()
# Create imported target pangolin
add_library(pangolin SHARED IMPORTED)
set_target_properties(pangolin PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3;${_IMPORT_PREFIX}/include"
INTERFACE_LINK_LIBRARIES "rt;pthread;/usr/lib/arm-linux-gnueabihf/libGL.so;/usr/lib/arm-linux-gnueabihf/libGLU.so;/usr/lib/arm-linux-gnueabihf/libGLEW.so;/usr/lib/arm-linux-gnueabihf/libEGL.so;/usr/lib/arm-linux-gnueabihf/libSM.so;/usr/lib/arm-linux-gnueabihf/libICE.so;/usr/lib/arm-linux-gnueabihf/libX11.so;/usr/lib/arm-linux-gnueabihf/libXext.so;rt;pthread;/usr/lib/arm-linux-gnueabihf/libdc1394.so;/usr/lib/arm-linux-gnueabihf/libpng.so;/usr/lib/arm-linux-gnueabihf/libz.so;/usr/lib/arm-linux-gnueabihf/libjpeg.so;/usr/lib/arm-linux-gnueabihf/libtiff.so;/usr/lib/arm-linux-gnueabihf/libIlmImf.so"
INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "/usr/include;/usr/include;/usr/include;/usr/local/include/eigen3"
)
if(CMAKE_VERSION VERSION_LESS 2.8.12)
message(FATAL_ERROR "This file relies on consumers using CMake 2.8.12 or greater.")
endif()
# Load information for each installed configuration.
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
file(GLOB CONFIG_FILES "${_DIR}/PangolinTargets-*.cmake")
foreach(f ${CONFIG_FILES})
include(${f})
endforeach()
# Cleanup temporary variables.
set(_IMPORT_PREFIX)
# Loop over all imported files and verify that they actually exist
foreach(target ${_IMPORT_CHECK_TARGETS} )
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
if(NOT EXISTS "${file}" )
message(FATAL_ERROR "The imported target \"${target}\" references the file
\"${file}\"
but this file does not exist. Possible reasons include:
* The file was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and contained
\"${CMAKE_CURRENT_LIST_FILE}\"
but not all the files it references.
")
endif()
endforeach()
unset(_IMPORT_CHECK_FILES_FOR_${target})
endforeach()
unset(_IMPORT_CHECK_TARGETS)
# This file does not depend on other imported targets which have
# been exported from the same project but in a separate export set.
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
cmake_policy(POP)
how to show the path of the file for the one that we search using find_package( )?
CMAKE_PREFIX_PATH
Semicolon-separated list of directories specifying installation prefixes to be searched by the find_package()...
set(CMAKE_PREFIX_PATH /home/users/rootf/usr/local/lib)
# additionalllly I also do a precaution
set(CMAKE_IGNORE_PATH / /bin /include /usr/lib /usr/local/lib)
You might also to manipulate with CMAKE_FIND_USE_*_PATH variables.

Create CMake/CPack <Library>Config.cmake for shared library

I have the simplest possible c-library which builds and is packed using the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project (libfoo C)
add_library(foo SHARED impl.c)
target_link_libraries(foo)
install(TARGETS foo LIBRARY DESTINATION lib/)
install(FILES public_header.h DESTINATION include/libfoo)
set(CPACK_GENERATOR "TGZ")
include(CPack)
Working example is located here: https://github.com/bjarkef/cmake-simple/tree/master/libfoo
I execute mkdir -p build; (cd build/; cmake ../; make all package;) to build a .tar.gz package with the compiled shared library along with its public header file. This is all working fine.
Now I wish to modify the CMakeLists.txt to create the FooConfig.cmake and FooConfigVersion.cmake files needed for CMake find_package in a different project to find the foo library. How do I do this?
I have discovered I should used the CMakePackageConfigHelpers: configure_package_config_file and write_basic_package_version_file, and I should create a FooLibraryConfig.cmake.in file. However I cannot figure out how to put it all together.
Note that it is important the the resulting .cmake files only contains relative paths.
I have cmake module included in the top level CmakeList.txt:
# Generate and install package config files
include(PackageConfigInstall)
Within the generic PackageConfigInstall.cmake file, the config files are created from the cmake.in files, and installed. This module can be reused for other packages.
include(CMakePackageConfigHelpers)
# Generate package config cmake files
set(${PACKAGE_NAME}_LIBRARY_NAME ${CMAKE_SHARED_LIBRARY_PREFIX}${PACKAGE_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX})
configure_package_config_file(${PACKAGE_NAME}-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_DIR}/${PACKAGE_NAME}
PATH_VARS LIB_INSTALL_DIR INCLUDE_INSTALL_DIR APP_INCLUDE_INSTALL_DIR )
configure_file(${PACKAGE_NAME}-config-version.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake #ONLY)
# Install package config cmake files
install(
FILES
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}-config-version.cmake
DESTINATION
${CMAKE_INSTALL_DIR}/${PACKAGE_NAME}
COMPONENT
devel
)
You'll need a package file for your library, such as your_lib-config.cmake.in, which will become your_lib-config.cmake. This will contain the include and library variables that can be used.
get_filename_component(YOUR_LIB_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
# flag required by CMakePackageConfigHelpers
#PACKAGE_INIT#
set_and_check(YOUR_LIB_INCLUDE_DIR #PACKAGE_YOUR_LIB_INCLUDE_INSTALL_DIR#/hal)
set_and_check(YOUR_LIB_LIBRARY #PACKAGE_LIB_INSTALL_DIR#/#CMAKE_STATIC_LIBRARY_PREFIX##PROJECT_NAME_LIB##CMAKE_STATIC_LIBRARY_SUFFIX#)
set_and_check(YOUR_LIB_LIBRARIES #PACKAGE_LIB_INSTALL_DIR#/#CMAKE_STATIC_LIBRARY_PREFIX##PROJECT_NAME_LIB##CMAKE_STATIC_LIBRARY_SUFFIX#)
You'll also want a config-version.cmake.in file like this:
set(PACKAGE_VERSION #PACKAGE_VERSION#)
# Check whether the requested PACKAGE_FIND_VERSION is compatible
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_COMPATIBLE FALSE)
else()
set(PACKAGE_VERSION_COMPATIBLE TRUE)
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
set(PACKAGE_VERSION_EXACT TRUE)
endif()
endif()
There's quite a bit to the packaging scripts to get it all to work just right. I went through a lot of trial and error to finally get something that works on different targets (both linux server and embedded target). I might have left something out, so please just comment and I'll update answer.

CPack / CMake: Different installation prefixes per CPACK_GENERATOR

How can I specify different installation prefixes for the different CPACK_GENERATORs?
For example:
the DEB package should be installed to /opt/project
the TGZ archive should consist only of the project directory
From the documentation I understood that I would have to use the CPACK_PROJECT_CONFIG_FILE variable. Using that, it should be possible to achieve the desired goal. However, it did not work for me.
This is my CPack configuration:
set(CPACK_GENERATOR "DEB;TGZ")
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_SOURCE_DIR}/cmake/package.linux.txt)
And this is my ${CMAKE_SOURCE_DIR}/cmake/package.linux.txt file:
IF (CPACK_GENERATOR MATCHES "DEB")
set(CPACK_NATIVE_INSTALL_DIRECTORY "/opt")
set(CMAKE_INSTALL_PREFIX "/opt")
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
set(CPACK_INSTALL_DIRECTORY "/opt")
ELSEIF(CPACK_GENERATOR MATCHES "TGZ")
set(CPACK_NATIVE_INSTALL_DIRECTORY "")
set(CMAKE_INSTALL_PREFIX "")
set(CPACK_PACKAGING_INSTALL_PREFIX "")
set(CPACK_INSTALL_DIRECTORY "")
ENDIF()
I have made sure that all files get parsed using MESSAGE() directives, but the prefix of my packages is always /usr/local.
Finally, I found out what was wrong. I had the CPACK_SET_DESTDIR flag set. This makes CPACK append usr/local to the directory containing the binaries of the compilation. After removing the corresponding SET() directive, everything worked like a charm.
For the record I will provide you with my minimal working example.
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(stripped-down C)
add_executable(main main.c)
install(TARGETS main
RUNTIME DESTINATION bin
)
set(CPACK_GENERATOR "DEB;TGZ")
set(CPACK_PROJECT_CONFIG_FILE ${CMAKE_SOURCE_DIR}/package.txt)
set(CPACK_PACKAGE_CONTACT "Some One <some.one#somewhere.com>")
include(CPack)
${CMAKE_SOURCE_DIR}/package.txt:
IF (CPACK_GENERATOR MATCHES "DEB")
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")
ELSEIF(CPACK_GENERATOR MATCHES "TGZ")
set(CPACK_PACKAGING_INSTALL_PREFIX "")
ENDIF()