4、CPack配置文件详解:CPackConfig.cmake文件结构、常用变量、设置包描述信息
好,咱们进入第四章。说实话,很多人在CMake里折腾半天,最后卡在打包这一步,就是因为CPackConfig.cmake没写对。这个文件说白了就是CPack的“总控台”,你告诉它包叫什么名字、版本号多少、谁来维护,它才能给你生成一个像样的安装包。
我个人习惯,每次新建项目都会先把这个文件搭好骨架。哪怕后面再改,也比最后手忙脚乱强。今天咱们就把这个文件掰开揉碎,看看里面到底有哪些门道。
4.1 CPackConfig.cmake 文件结构
这个文件其实就是一个普通的CMake脚本文件。CPack在打包时会读取它,然后根据里面的变量决定怎么干活。结构上很简单,就是一堆set()命令。
我见过有人把几百行配置全塞在一个文件里,看着就头疼。其实可以拆成几块:
- 基础信息区:包名、版本、描述
- 平台配置区:生成器类型、安装路径
- 依赖与组件区:需要打包哪些库、哪些文件
- 高级选项区:签名、压缩、许可证等
嗯,这里要注意,CPackConfig.cmake 必须和你的 CMakeLists.txt 放在同一级目录,或者通过 -C 参数指定路径。否则CPack找不到它,直接报错。
# 一个典型的 CPackConfig.cmake 骨架
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A useful application")
set(CPACK_GENERATOR "TGZ;DEB;RPM")
4.2 核心常用变量详解
CPack的变量很多,但常用的就那么十几个。我把它们分成三类,咱们一个一个看。
4.2.1 包标识变量
| 变量名 | 作用 | 示例值 |
|---|---|---|
CPACK_PACKAGE_NAME |
包名,会出现在安装包文件名中 | "MyApp" |
CPACK_PACKAGE_VERSION |
版本号,通常从CMakeLists.txt传入 | "2.1.0" |
CPACK_PACKAGE_VENDOR |
供应商/组织名称 | "MyCompany" |
CPACK_PACKAGE_CONTACT |
维护者邮箱 | "dev@mycompany.com" |
我在项目中遇到过一个问题:有人把 CPACK_PACKAGE_NAME 设成了带空格的字符串,结果生成的DEB包名直接非法。记住,包名里不要有空格,用下划线或者连字符代替。
4.2.2 版本与描述变量
版本号这块,我建议你从CMakeLists.txt里用 project() 命令定义好,然后通过 set() 传过来。这样版本号只维护一份,不会出现CMakeLists.txt里是1.0,CPackConfig里还是0.9的尴尬。
# 在 CMakeLists.txt 中
project(MyApp VERSION 1.2.3)
# 在 CPackConfig.cmake 中
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
描述信息也很重要。很多Linux发行版的包管理器会读取这些字段:
CPACK_PACKAGE_DESCRIPTION_SUMMARY:一句话简介,显示在包列表里CPACK_PACKAGE_DESCRIPTION_FILE:指向一个包含详细描述的文本文件CPACK_RESOURCE_FILE_LICENSE:许可证文件路径CPACK_RESOURCE_FILE_README:README文件路径
CPACK_PACKAGE_DESCRIPTION_SUMMARY 不要写太长,50个字符以内最佳。DEB包的Description字段如果太长会被截断,你想想看,用户看到一半就没了,多难受。
4.2.3 生成器与路径变量
CPack支持多种打包格式,通过 CPACK_GENERATOR 指定。可以同时指定多个,用分号隔开:
set(CPACK_GENERATOR "TGZ;DEB;RPM;NSIS")
常用的生成器有:
- TGZ:tar.gz压缩包,跨平台通用
- DEB:Debian/Ubuntu包
- RPM:Red Hat/Fedora包
- NSIS:Windows安装程序
- DragNDrop:macOS的.dmg包
安装路径相关的变量也很关键:
| 变量名 | 说明 |
|---|---|
CPACK_PACKAGE_INSTALL_DIRECTORY |
安装到系统后的顶层目录名 |
CPACK_SET_DESTDIR |
是否启用DESTDIR机制 |
CPACK_INSTALL_PREFIX |
安装前缀,默认是 /usr/local |
CPACK_INSTALL_PREFIX,结果默认装到了 /usr/local,而目标系统的根目录只有50MB空间,直接撑爆了。后来我改成 /opt/myapp,问题解决。
4.3 设置包描述信息
描述信息不只是给用户看的,也是给包管理器看的。比如在Ubuntu上执行 apt show myapp,显示的内容就来自这些变量。
我一般会准备三个文件:
- LICENSE.txt:许可证文本,比如MIT、GPL
- README.md:项目简介、构建方式、使用说明
- ChangeLog.txt:版本变更记录
然后在CPackConfig里这样引用:
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.txt")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/ChangeLog.txt")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A lightweight HTTP server for embedded systems")
对于DEB包,还有几个专属变量:
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "John Doe <john@example.com>")
set(CPACK_DEBIAN_PACKAGE_SECTION "net")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "https://myapp.example.com")
RPM包也有对应的:
set(CPACK_RPM_PACKAGE_GROUP "Applications/Internet")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")
set(CPACK_RPM_PACKAGE_URL "https://myapp.example.com")
set(CPACK_RPM_PACKAGE_RELEASE "1")
4.4 一个完整的示例
最后,给你看一个我实际项目中用过的CPackConfig.cmake。不算复杂,但该有的都有了:
# ============================================
# CPack 配置文件
# 项目:MiniWebServer
# 版本:从 CMakeLists.txt 自动获取
# ============================================
# ---- 基础信息 ----
set(CPACK_PACKAGE_NAME "MiniWebServer")
set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}")
set(CPACK_PACKAGE_VENDOR "Example Corp")
set(CPACK_PACKAGE_CONTACT "support@example.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A minimal HTTP server for IoT devices")
# ---- 描述文件 ----
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
# ---- 生成器 ----
set(CPACK_GENERATOR "TGZ;DEB")
# ---- 安装路径 ----
set(CPACK_INSTALL_PREFIX "/opt/miniwebserver")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "MiniWebServer")
# ---- DEB 专属配置 ----
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Example Corp <support@example.com>")
set(CPACK_DEBIAN_PACKAGE_SECTION "httpd")
set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libssl1.1, libc6 (>= 2.28)")
# ---- 组件打包(可选) ----
# set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE ON)
看到没?核心就是把这些变量填对。你只要照着这个模板改,基本不会出大问题。
好,这一章就到这里。下一章咱们聊聊怎么用 install() 命令把文件安排得明明白白,那是打包前最重要的一步。