如何用CPack/CMake限制RHEL/CentOS包安装版本?含Debian方案
我来帮你搞定这个问题!你想要的效果是让RHEL7的包在RHEL8上安装直接报错,同时不想折腾自定义spec或deb控制文件,用现有的CPack/CMake机制就能实现,分RPM和DEB两种情况给你详细说:
一、针对RHEL/CentOS(RPM包)的实现方案
方案1:用原生依赖限制(最推荐)
不用写自定义spec,直接在CMakeLists.txt里配置CPack的RPM依赖变量就行。RHEL和CentOS都原生支持redhat-release这个虚拟包,不管是CentOS的centos-release还是RHEL的官方release包,都会提供这个虚拟包的版本信息。
比如你要构建仅支持RHEL7/CentOS7的包,就在CMake里加这段:
if(UNIX AND NOT APPLE) # 限定依赖RHEL7及以上、低于8的版本 set(CPACK_RPM_PACKAGE_REQUIRES "redhat-release >= 7.0, redhat-release < 8.0") # 如果是构建RHEL8的包,就改成 "redhat-release >= 8.0, redhat-release < 9.0" endif()
这样用户在RHEL8上装这个包时,rpm会直接检测到依赖不满足,给出标准的错误提示,完全符合你的需求,而且不会因为系统小版本升级(比如CentOS7.6升到7.9)导致依赖失效。
方案2:预安装脚本自定义错误提示
如果你想要更个性化的错误信息,比如直接提示“此包仅适用于RHEL7/CentOS7”,可以加个预安装脚本:
先在CMake里指定脚本路径:
set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/rpm_preinstall.sh")
然后写rpm_preinstall.sh脚本:
#!/bin/bash # 获取当前系统的RHEL主版本号 RELEASE_VER=$(rpm -E %rhel) if [ "$RELEASE_VER" -ne 7 ]; then echo "错误:此包仅适用于RHEL7/CentOS7" >&2 exit 1 fi
这个脚本会在安装前执行,检查系统版本,不符合就直接终止安装,错误信息完全由你自定义。
关于你提到的特定release包依赖的问题
你说的依赖centos-release-8.2确实不靠谱,因为系统小版本升级后这个包名就变了。而用redhat-release的版本范围依赖就没这个问题,不管是CentOS还是RHEL,主版本号是固定的,7.x都满足>=7.0 <8.0,完美适配。
二、针对Debian/Ubuntu(DEB包)的实现方案
同样用CPack就能搞定,分两种方案:
方案1:版本化依赖(推荐)
Debian系的base-files包版本号直接对应发行版的主版本,比如Debian10的base-files是10.x,Ubuntu20.04的是20.04.x。你可以在CMake里配置依赖:
if(UNIX AND NOT APPLE AND NOT EXISTS "/etc/redhat-release") # 比如限定仅支持Debian10/Ubuntu20.04及以上、低于Debian11/Ubuntu22.04的版本 set(CPACK_DEBIAN_PACKAGE_DEPENDS "base-files >= 10.0, base-files < 11.0") # 如果是Debian11的包,就改成 "base-files >= 11.0, base-files < 12.0" endif()
这样apt会自动检查依赖,不符合就阻止安装,提示标准的依赖缺失信息。
方案2:预安装脚本自定义提示
如果想要个性化错误信息,同样可以加预安装脚本:
在CMake里指定脚本:
set(CPACK_DEBIAN_PRE_INSTALL_SCRIPT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/debian_preinstall.sh")
然后写debian_preinstall.sh:
#!/bin/bash # 读取系统版本信息 source /etc/os-release # 这里以Debian10为例,你可以改成目标版本号 if [ "$VERSION_ID" != "10" ]; then echo "错误:此包仅适用于Debian10(Buster)或等价的Ubuntu版本" >&2 exit 1 fi
脚本会读取/etc/os-release里的版本ID,不符合就终止安装,错误信息你可以随便改。
总结
优先选版本化依赖的方式,这是包管理系统原生支持的,最稳定,错误提示也标准;如果需要自定义错误文案,就用预安装脚本。两种方式都不需要写自定义的spec或deb控制文件,完全适配你现有的构建流程。
内容的提问来源于stack exchange,提问作者Bruce Adams

