CPack入门:CPack是什么、CPack与CMake的关系、CPack安装与基本配置

说实话,很多做C++项目的朋友,CMake用得挺溜,但一到「把项目打包成安装包」这一步就卡住了。我自己早年也踩过这个坑——项目编译通过了,结果交付的时候,要么手动拷贝文件,要么写一堆乱七八糟的脚本。后来接触了CPack,才发现原来CMake生态里早就给你准备好了打包工具。

这一章,我们就来聊聊CPack。嗯,别把它想得太复杂,它其实就是CMake的「亲兄弟」,专门负责把编译好的东西打包成你想要的格式。

CPack是什么?

CPack,全称是CMake Packager。说白了,它是一个跨平台的打包工具。你写好了CMakeLists.txt,用CMake配置、构建完项目,CPack就能帮你把生成的可执行文件、库文件、配置文件、文档等等,一股脑打包成一个安装包。

它支持什么格式?我列一下你感受感受:

  • Windows:NSIS、WiX、ZIP
  • macOS:DMG、Bundle、PackageMaker
  • Linux:DEB、RPM、TGZ、STGZ
  • 跨平台:ZIP、TAR.GZ、TAR.BZ2

你看,几乎覆盖了主流平台。我在项目中遇到过最典型的场景:同一个项目,要给Windows用户发exe安装包,给Ubuntu用户发deb包,给CentOS用户发rpm包。如果没有CPack,你得写三套打包脚本。有了它,一套CMakeLists.txt搞定。

核心要点:CPack不是构建工具,它是打包工具。它不编译代码,它只负责把编译好的产物整理成安装包。

CPack与CMake的关系

这个问题很多人问过我。CPack和CMake到底是什么关系?

其实很简单。CMake负责「怎么编译」,CPack负责「怎么打包」。它们共用同一个CMakeLists.txt里的信息。你在CMakeLists.txt里定义的安装规则(install命令),CPack直接拿来用。

我画了一张图,帮你理清这个关系:

CMake 与 CPack 协作流程 CMake 配置 + 构建项目 CPack 打包成安装包 读取安装规则 CMakeLists.txt install() 命令定义安装规则 安装包 .deb / .rpm / .dmg / .exe 间接引用 你只需要写一份 CMakeLists.txt,CMake 和 CPack 各取所需

从图上你能看出来,CMakeLists.txt是核心。你写好install规则,CMake用它来构建,CPack用它来打包。两者配合得天衣无缝。

小提示:如果你已经在CMakeLists.txt里写好了install命令,那CPack的配置工作其实已经完成了一半。CPack只是在此基础上加了一些打包相关的参数。

CPack的安装

安装CPack?其实你大概率已经装好了。因为CPack是CMake的一部分。你装CMake的时候,CPack就跟着一起装进来了。

验证一下很简单,打开终端敲:

cpack --version

如果看到版本号输出,说明已经装好了。我见过有人折腾半天去单独下载CPack,其实完全没必要。

不同平台的安装方式:

平台 安装方式 备注
Ubuntu/Debian sudo apt install cmake CPack 自动包含
CentOS/RHEL sudo yum install cmake CPack 自动包含
macOS brew install cmake CPack 自动包含
Windows 下载CMake安装包 勾选「Add to PATH」

我个人习惯在Linux上开发,所以经常用apt安装。装完之后,cpack命令就能直接用了。

CPack的基本配置

配置CPack,主要有两种方式:

  1. 在CMakeLists.txt里直接写:用set命令设置CPack相关的变量。
  2. 单独写CPackConfig.cmake文件:把打包配置独立出来。

我建议初学者先用第一种方式,简单直接。等项目复杂了,再考虑拆分文件。

来看一个最基础的例子。假设你有一个简单的项目,编译后生成一个可执行文件myapp。你想把它打包成ZIP和DEB两种格式。

CMakeLists.txt的内容:

cmake_minimum_required(VERSION 3.15)
project(MyApp VERSION 1.0.0)

add_executable(myapp main.cpp)

# 安装规则:把myapp安装到bin目录
install(TARGETS myapp DESTINATION bin)

# ---------- CPack 配置 ----------
set(CPACK_GENERATOR "ZIP;DEB")
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "1.0.0")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A simple example application")
set(CPACK_PACKAGE_VENDOR "Your Company")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "your@email.com")

然后执行:

mkdir build && cd build
cmake ..
make
cpack

你会看到生成了两个文件:MyApp-1.0.0-Linux.zip 和 MyApp-1.0.0-Linux.deb。

注意:CPack默认的包名格式是 <PackageName>-<Version>-<Platform>.<ext>。你可以通过设置 CPACK_PACKAGE_FILE_NAME 来自定义。

常用CPack变量一览

这里我列几个最常用的变量,你记一下:

变量名 作用 示例值
CPACK_GENERATOR 指定打包格式 ZIP;DEB;RPM;NSIS
CPACK_PACKAGE_NAME 包名 MyApp
CPACK_PACKAGE_VERSION 版本号 1.0.0
CPACK_PACKAGE_VENDOR 供应商信息 Your Company
CPACK_PACKAGE_CONTACT 联系方式 your@email.com
CPACK_PACKAGE_DESCRIPTION_SUMMARY 简短描述 A useful tool
CPACK_PACKAGE_FILE_NAME 自定义输出文件名 MyApp-1.0.0
CPACK_OUTPUT_FILE_PREFIX 输出目录 ./packages

避坑指南:我曾经在配置DEB包时,忘了设置 CPACK_DEBIAN_PACKAGE_MAINTAINER,结果生成的deb包死活装不上。后来查了半天,才发现这个变量是必填的。嗯,DEB包规范要求维护者信息不能为空。

一个完整的入门示例

我们来写一个稍微完整点的例子。假设项目结构如下:

myapp/
├── CMakeLists.txt
├── src/
│   └── main.cpp
├── include/
│   └── myapp.h
└── config/
    └── myapp.conf

CMakeLists.txt:

cmake_minimum_required(VERSION 3.15)
project(MyApp VERSION 2.0.0 LANGUAGES CXX)

# 添加可执行文件
add_executable(myapp src/main.cpp)
target_include_directories(myapp PRIVATE include)

# 安装可执行文件
install(TARGETS myapp DESTINATION bin)

# 安装配置文件
install(FILES config/myapp.conf DESTINATION etc/myapp)

# 安装头文件(供其他项目使用)
install(DIRECTORY include/ DESTINATION include/myapp)

# ---------- CPack 配置 ----------
set(CPACK_GENERATOR "ZIP;DEB;RPM")
set(CPACK_PACKAGE_NAME "MyApp")
set(CPACK_PACKAGE_VERSION "2.0.0")
set(CPACK_PACKAGE_VENDOR "MyCompany")
set(CPACK_PACKAGE_CONTACT "support@mycompany.com")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyApp - a demonstration application")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")

# DEB 专属配置
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "support@mycompany.com")
set(CPACK_DEBIAN_PACKAGE_SECTION "utils")

# RPM 专属配置
set(CPACK_RPM_PACKAGE_GROUP "Applications/System")
set(CPACK_RPM_PACKAGE_LICENSE "MIT")

执行打包:

mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make
cpack

你会看到生成了三个包:ZIP、DEB、RPM。每个包里的文件结构都是按照你定义的install规则来的。

小技巧:设置 CMAKE_INSTALL_PREFIX 很重要。它决定了安装包里的文件路径前缀。比如你设成 /usr,那可执行文件就会在 /usr/bin 下,配置文件在 /usr/etc/myapp 下。这个路径会直接反映到安装包里。

CPack的工作流程

最后,我总结一下CPack的完整工作流程。你心里有个数:

  1. 编写CMakeLists.txt:定义项目、构建目标、安装规则。
  2. 配置CPack变量:指定打包格式、包信息等。
  3. 构建项目:cmake + make,生成可执行文件和库。
  4. 运行cpack:CPack读取安装规则和配置,生成安装包。

说白了,你只需要关注第1步和第2步。第3步和第4步都是机械操作。这也是CPack的魅力所在——把重复劳动交给工具,你只负责定义规则。

好了,这一章的内容就到这里。CPack入门其实不难,关键是理解它和CMake的协作关系,以及掌握那几个核心变量。下一章我们会深入聊聊CPack的生成器,看看不同平台下的打包格式有什么门道。


公众号:蓝海资料掘金营,微信 deep3321