3、第一个CPack项目:创建最小CMake项目、添加CPack配置、生成第一个安装包

好,咱们正式开始动手了。

前面两章聊了CPack能干什么,以及它和CMake是什么关系。说实话,光说不练假把式。这一章,我带你从零开始,亲手搭建一个最小的CPack项目。

你不需要懂复杂的C++代码,甚至不需要有现成的项目。咱们就造一个最简单的“Hello World”工程,然后给它穿上CPack的外衣,生成一个实实在在的安装包。

嗯,这个过程走通了,后面再复杂的项目,无非是在这个骨架上添砖加瓦。

3.1 创建最小CMake项目

首先,咱们得有个能被CMake管理的项目。我习惯在桌面上新建一个文件夹,就叫 cpack_demo。

在里面创建两个文件:CMakeLists.txt 和 main.cpp。

main.cpp 的内容,简单到不能再简单:

#include <iostream>

int main() {
    std::cout << "Hello from CPack!" << std::endl;
    return 0;
}

CMakeLists.txt 的内容,也是最小配置:

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

add_executable(myapp main.cpp)

install(TARGETS myapp DESTINATION bin)

这里我重点说一下 install 这一行。很多初学者会忽略它,觉得程序能编译运行就行了。但CPack打包,打的就是“安装后的内容”。

如果你不告诉CMake“安装时要把myapp放到哪个目录”,CPack就不知道要打包什么。说白了,install 命令就是给CPack画了个圈,告诉它:“圈里的东西,才是要打包的。”

我的习惯: 哪怕项目再小,我也会先写 install 命令。这能强迫你从一开始就思考“用户拿到安装包后,文件应该怎么组织”。

3.2 添加CPack配置

CMake项目有了,接下来就是CPack的配置。你可以在 CMakeLists.txt 里直接写,也可以单独创建一个 CPackConfig.cmake 文件。我个人更喜欢后者,配置多了好管理。

在 cpack_demo 目录下,新建 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 simple CPack demo")

set(CPACK_GENERATOR "TGZ;DEB;RPM")

include(CPack)

这里我设置了三个生成器:TGZ(tar.gz压缩包)、DEB(Debian包)、RPM(Red Hat包)。

你可能会问:“为什么一次生成这么多格式?”

其实在开发阶段,我通常只开TGZ,因为快。但到了发布阶段,我会把DEB和RPM都加上。为什么呢?因为我在项目中遇到过,同一个二进制包在Ubuntu和CentOS上安装路径不一样,提前用不同格式验证一下,能省去后面很多麻烦。

关键点: 别忘了在 CMakeLists.txt 末尾加上 include(CPack)。如果你用了单独的配置文件,就在配置文件的末尾加。这一步是激活CPack的开关,少了它,后面所有操作都白搭。

3.3 生成第一个安装包

配置写完了,咱们来见证奇迹。

打开终端,进入 cpack_demo 目录,执行标准的CMake构建流程:

mkdir build
cd build
cmake ..
make

这时候你应该能看到 myapp 可执行文件被编译出来了。但别急,咱们要的是安装包。

在 build 目录下,执行:

cpack

如果一切顺利,你会看到类似这样的输出:

CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: MyApp
CPack: - Install project: MyApp
CPack: Create package
CPack: - package: /path/to/cpack_demo/build/MyApp-1.0.0-Linux.tar.gz generated.
CPack: Create package using DEB
CPack: - package: /path/to/cpack_demo/build/MyApp-1.0.0-Linux.deb generated.
CPack: Create package using RPM
CPack: - package: /path/to/cpack_demo/build/MyApp-1.0.0-Linux.rpm generated.

打开 build 目录,你会看到三个安装包整整齐齐地躺在那里。

我曾经踩过的坑: 第一次运行 cpack 时,如果提示找不到 cpack 命令,多半是CMake没装全,或者没加到PATH里。另外,生成DEB包需要系统安装 dpkg,生成RPM包需要 rpmbuild。如果某个生成器报错,可以先把它从 CPACK_GENERATOR 里去掉,先跑通TGZ再说。

3.4 验证安装包内容

包生成了,怎么知道里面装的对不对?

对于TGZ包,你可以直接解压查看:

tar -tzf MyApp-1.0.0-Linux.tar.gz

你应该能看到类似这样的结构:

MyApp-1.0.0-Linux/
MyApp-1.0.0-Linux/bin/
MyApp-1.0.0-Linux/bin/myapp

嗯,myapp 被正确地放在了 bin 目录下。这就是我们在 install 命令里指定的目标路径。

对于DEB包,可以用 dpkg-deb -c 查看:

dpkg-deb -c MyApp-1.0.0-Linux.deb

你会看到安装路径变成了 /usr/local/bin/myapp。这是CPack根据DEB的规范自动调整的。你看,不同格式的包,安装路径的约定是不一样的。CPack帮我们处理了这些差异。

一个小技巧: 我经常用 cpack -G TGZ 单独生成TGZ包来做快速验证。等所有配置都调好了,再一次性生成所有格式。这样能节省不少调试时间。

3.5 本章小结

咱们回顾一下,这一章做了三件事:

  • 创建了一个包含 install 命令的最小CMake项目
  • 添加了CPack配置文件,指定了包名、版本和生成器
  • 用 cpack 命令生成了TGZ、DEB、RPM三种格式的安装包

说白了,CPack的核心流程就三步:写install → 配CPack → 跑cpack。后面的所有高级功能,都是在这个基础上叠加的。

下一章,咱们会深入聊聊 install 命令的各种玩法。毕竟,安装规则写得越精细,生成的安装包就越专业。

嗯,动手试试吧。有问题随时回来翻翻这一章。