The Requirement
I want to have multi versions of a library installed in one place(e.g. the default system prefix path) using CMake to be used like: find_package(Package 1.0.0 REQUIRED)
.
- Why just don't set some paths?
- Because I'm an idiot at remembering paths and flags and other related stuff and I think it's the CMake's
find_package
job to handle it.
- Because I'm an idiot at remembering paths and flags and other related stuff and I think it's the CMake's
The Problem
The find_package
's version parameter is just an ordinary parameter that will be passed to the package *VersionConfig.cmake
file for version checking and if that file doesn't exists CMake will treat it as an error. So we couldn't install different version in the same place.
Minimal CMake Configuration
file(WRITE Library.H "void Function();")
file(WRITE Library.C "void Function() {}")
add_library(Library SHARED Library.H Library.C)
target_include_directories(Library
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/Library>
)
set_target_properties(Library PROPERTIES VERSION 1.0.0)
install(TARGETS Library EXPORT LibraryConfig)
install(FILES Library.H DESTINATION include/Library)
install(EXPORT LibraryConfig DESTINATION lib/cmake/Library)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${PROJECT_BINARY_DIR}/LibraryConfigVersion.cmake
VERSION 1.0.0
COMPATIBILITY SameMajorVersion
)
install(
FILES ${PROJECT_BINARY_DIR}/LibraryConfigVersion.cmake
DESTINATION lib/cmake/Library
)
Possible Solution
I just apply version to the target name in form of ${PROJECT_NAME}-${PROJECT_VERSION}
:
- I changed the export name:
install(TARGETS Library EXPORT Library-1.0.0Config)
install(
EXPORT Library-1.0.0Config
DESTINATION lib/cmake/Library-1.0.0Config
)
- And the
INSTALL_INTERFACE
for the include directories:
target_include_directories(Library
PUBLIC
$<INSTALL_INTERFACE:include/Library-1.0.0>
)
- And the
OUTPUT_NAME
property of the target:
set_target_properties(Library
PROPERTIES
OUTPUT_NAME Library-1.0.0
)
The result:
file(WRITE Library.H "void Function();")
file(WRITE Library.C "void Function() {}")
add_library(Library SHARED Library.H Library.C)
target_include_directories(Library
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/Library-1.0.0>
)
set_target_properties(Library PROPERTIES OUTPUT_NAME Library-1.0.0)
install(TARGETS Library EXPORT Library-1.0.0Config)
install(FILES Library.H DESTINATION include/Library-1.0.0)
install(EXPORT Library-1.0.0Config DESTINATION lib/cmake/Library-1.0.0)
But with this approach, I always have to specify the version: find_package(Target-1.0.0 REQUIRED)
.
CodePudding user response:
You are working in Config Mode of find_package
, so the search mode according to the documents is like:
<prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/ (U)
<prefix>/(lib/<arch>|lib*|share)/<name>*/ (U)
<prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/ (U)
So you need to:
- Change the
INSTALL_INTERFACE
to point to a directory tagged with the library version(with whatever policy you prefer for version matching). - Install your package's config files in a directory tagged with the library version(again with your preferred version matching policy).
- Provide a version config file and installed it beside the config files. A version config file is required for version matching.
- Change the
OUTPUT_NAME
property of the target to a name tagged with the version.- If you instead set
VERSION
orSOVERSION
property, the result will be a non-version tagged symlink to the tagged one. It will be overridden by other versions and It could cause problems if anyone used it without using CMake.
- If you instead set
So your sample with above modifications could be like:
file(WRITE Library.H "void Function();")
file(WRITE Library.C "void Function() {}")
add_library(Library SHARED Library.H Library.C)
target_include_directories(Library
PUBLIC
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
$<INSTALL_INTERFACE:include/Library-1.0.0>
)
set_target_properties(Library PROPERTIES OUTPUT_NAME 1.0.0)
install(TARGETS Library EXPORT LibraryConfig)
install(FILES Library.H DESTINATION include/Library-1.0.0)
install(EXPORT LibraryConfig DESTINATION lib/cmake/Library-1.0.0)
include(CMakePackageConfigHelpers)
write_basic_package_version_file(
${PROJECT_BINARY_DIR}/LibraryConfigVersion.cmake
VERSION 1.0.0
COMPATIBILITY SameMajorVersion
)
install(
FILES ${PROJECT_BINARY_DIR}/LibraryConfigVersion.cmake
DESTINATION lib/cmake/Library-1.0.0
)
With this approach doesn't matter how many version of the library is installed using the same prefix path, the only important thing is the EXACT version name. And the usage could be requesting for a version find_package(Target 1.0.0)
or the last available version find_package(Target)
(based on the search policy and the version matching policy).