如何使用CMake为仅含头文件的INTERFACE库设置版本?
Great question! This is a common gotcha with INTERFACE libraries in CMake because they don’t represent a binary target—so properties like VERSION and SOVERSION aren’t in their default allowed property list (hence the error you’re seeing). Let’s break down the solutions based on your CMake version:
Option 1: Use CMake 3.24+ (Simplest Approach)
Starting with CMake 3.24, the VERSION and SOVERSION properties were added to the allowed list for INTERFACE targets. You can use set_target_properties just like you would for a regular library:
add_library(MyHeaderOnlyLib INTERFACE) set_target_properties(MyHeaderOnlyLib PROPERTIES VERSION "1.2.3" SOVERSION "1" )
This makes the version properties available to any targets linking against your INTERFACE library, and works seamlessly with CMake’s package configuration system.
Option 2: For CMake < 3.24 (Workarounds)
If you’re stuck on an older CMake version, you’ll need to use alternative methods to expose version information:
Suboption 2a: Expose Version via Compile Definitions
You can directly pass version constants to consuming targets using target_compile_definitions:
add_library(MyHeaderOnlyLib INTERFACE) target_compile_definitions(MyHeaderOnlyLib INTERFACE MY_LIB_VERSION_MAJOR=1 MY_LIB_VERSION_MINOR=2 MY_LIB_VERSION_PATCH=3 MY_LIB_VERSION="1.2.3" )
Consuming code can then use these preprocessor defines directly.
Suboption 2b: Generate a Version Header File
A cleaner approach is to create a version header using configure_file, which lets you centralize version info and make it accessible via a header:
- Create a
version.h.intemplate:
#define MY_LIB_VERSION_MAJOR @MY_LIB_VERSION_MAJOR@ #define MY_LIB_VERSION_MINOR @MY_LIB_VERSION_MINOR@ #define MY_LIB_VERSION_PATCH @MY_LIB_VERSION_PATCH@ #define MY_LIB_VERSION "@MY_LIB_VERSION@"
- In your CMakeLists.txt, set the version variables and generate the header:
# Define version constants set(MY_LIB_VERSION_MAJOR 1) set(MY_LIB_VERSION_MINOR 2) set(MY_LIB_VERSION_PATCH 3) set(MY_LIB_VERSION "${MY_LIB_VERSION_MAJOR}.${MY_LIB_VERSION_MINOR}.${MY_LIB_VERSION_PATCH}") add_library(MyHeaderOnlyLib INTERFACE) # Generate the version header configure_file(version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h @ONLY) # Make the generated header available to consumers target_include_directories(MyHeaderOnlyLib INTERFACE $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}> $<INSTALL_INTERFACE:include> )
Consumers can now include <version.h> to access the version info.
Suboption 2c: Support Version Checking for find_package
If you want users to be able to do find_package(MyLib 1.2 REQUIRED), you need to generate a ConfigVersion.cmake file (regardless of CMake version):
include(CMakePackageConfigHelpers) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/MyHeaderOnlyLibConfigVersion.cmake VERSION ${MY_LIB_VERSION} COMPATIBILITY SameMajorVersion # Or another compatibility rule like SameMinorVersion/AnyNewerVersion ) # Install the config files so find_package can locate them install(FILES ${CMAKE_CURRENT_BINARY_DIR}/MyHeaderOnlyLibConfigVersion.cmake ${CMAKE_CURRENT_SOURCE_DIR}/MyHeaderOnlyLibConfig.cmake DESTINATION lib/cmake/MyHeaderOnlyLib ) # Install your INTERFACE target and exports install(TARGETS MyHeaderOnlyLib EXPORT MyHeaderOnlyLibTargets INCLUDES DESTINATION include ) install(EXPORT MyHeaderOnlyLibTargets FILE MyHeaderOnlyLibTargets.cmake DESTINATION lib/cmake/MyHeaderOnlyLib )
This ensures CMake can validate the version when users try to find your library.
内容的提问来源于stack exchange,提问作者user8183713

