CPack 入门指南

背景
CPack 是 CMake 2.4.2 之后的一个内置工具,用于创建软件的二进制包和源代码包。
CPack 在整个 CMake 工具链的位置。

CPack 支持打包的包格式有以下种类:
- 7Z (7-Zip file format)
- DEB (Debian packages)
- External (CPack External packages)
- IFW (Qt Installer Framework)
- NSIS (Null Soft Installer)
- NSIS64 (Null Soft Installer (64-bit))
- NuGet (NuGet packages)
- RPM (RPM packages)
- STGZ (Self extracting Tar GZip compression
- TBZ2 (Tar GZip compression)
- TXZ (Tar XZ compression)
- TZ (Tar Compress compression)
- ZIP (ZIP file format)
为什么要用打包工具
软件程序想要在生产环境快速被使用,就需要一个一键安装的安装包,这样生产环境就可以很方便的部署和使用。
选择 CPack 的原因
C++ 工程大部分都是用 CMake 配置编译, 而 CPack 是 CMake 内置的工具,支持打包成多种格式的安装包。因为是 CMake 的内置工具,所以使用的方式也是通过在 CMakeLists.txt 配置参数,就能达到我们的需求。使用起来很方便,容易上手。
如何安装 CPack
安装 CMake 的时候会把 CPack 一起安装了,直接通过 yum 或者 apt-get 安装即可。
一个简单的例子
基础配置
这里介绍如何打包 rpm 包,deb 的打包是一样的,区别在于一些配置。Cpack 打包 rpm 用的是 CPack RPM 生成器,用到的配置变量是以 CPACK_RPM_XXX 为前缀。最终通过 rpm-build 这个工具去打包,所以需要安装 rpm-build 这个工具,可以通过 sudo yum install -y rpm-build 安装。下面配置是用 3.14.5 的 CMake 进行测试的。
现在有一个工程 example,其目录结构如下:
example
|-- CMakeLists.txt // example 的主 CMakeLists.txt 文件
|-- Readme.txt
|-- License.txt
|-- src
| |-- CMakeLists.txt
| |-- MainA.cpp // 可执行文件 Aprogram 的源码
| |__ MainB.cpp // 可执行文件 Bprogram 的源码
|
|-- etc
| |-- CMakeLists.txt
| |-- A.conf // 可执行文件 Aprogram 的配置文件
| |__ B.conf // 可执行文件 Bprogram 的配置文件
|
|__ scripts
|-- preinst // 安装前执行的脚本
|-- postinst // 安装后执行的脚本
|-- prerm // 卸载前执行的脚本
|__ postrm // 卸载后执行的脚本
只需要在 example/CMakeLists.txt 文件里面添加如下配置
# 设置生成的安装包名字
set(CPACK_PACKAGE_NAME "example")
# 设置支持指定安装目录的控制为 ON
set(CPACK_SET_DESTDIR ON)
# 设置安装到的目录路径
set(CPACK_INSTALL_PREFIX "/home/vesoft/install")
# 这是生成的安装的版本号信息
set(CPACK_PACKAGE_VERSION "1.0.0")
# 设置 group 名字
set(CPACK_RPM_PACKAGE_GROUP "vesoft")
# 设置 vendor 名字
set(CPACK_PACKAGE_VENDOR "vesoft")
# 设置 license 信息
set(CPACK_RPM_PACKAGE_LICENSE "Apache 2.0 + Common Clause 1.0")
include(CPack)
执行 cmake 命令后, 你会发现当前目录下面多了两个文件 CPackConfig.cmake 和 CPackSourceConfig.cmake。 编译完成后,执行 cpack -G RPM 就可将文件打包成 rpm 包,当前目录下会生成一个 _CPack_Packages 目录和一个以 .rpm 为后缀名的文件 example-1.0.0-Linux.rpm,example-1.0.0-Linux.rpm 就是我们想要的安装包文件。
如果想要查看打包过程的详细输出,可以在命令后面添加 --verbose。CPack 是根据用户的配置生成_CPack_Packages/Linux/RPM/SPECS/example.spec 文件,然后让 rpm-build 用。
上面配置生成的安装包 example-1.0.0-Linux.rpm里面包含的文件如下:

️注意:假如安装时出现 file /home from install of example-1.0.0-1.x86_64 conflicts with file from package filesystem-3.2-25.el7.x86_64,那么需要在配置文件里面添加以下配置,让生成的 rpm 文件不包含 /home 和 /home/vesoft 。
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/home")
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/home/vesoft")
添加行为
我们要在安装前后、卸载前后做一些事情时,可以通过写相应的脚本文件:
- preinst:安装前脚本文件
- postinst:安装后脚本文件
- prerm:卸载前文件
- postrm:卸载后文件
在上述的 CMakeLists.txt 文件里面添加如下配置:
# 设置安装前执行的脚本文件 preinst
set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/preinst)
# 设置卸载前执行的脚本文件 prerm
set(CPACK_RPM_PRE_UNINSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/prerm)
# 设置安装后执行的脚本文件 postinst
set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/postinst)
# 设置卸载后执行的脚本文件 postrm
set(CPACK_RPM_POST_UNINSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/scripts/postrm)
CPack 会将上面配置的脚本里面的内容写到生成的 SPEC 文件里面去。
️注意:上述的四个脚本文件需要的权限是所有用户和用户组均能执行,创建完脚本文件后,通过 chmod 755 scripts/* 修改 scripts 目录下面的脚本文件的权限。
执行 sudo rpm -ivh example-1.0.0-Linux.rpm 命令会有以下输出

执行 sudo rpm -e example-1.0.0 会有以下输出

可以看到图片里面绿色和红色字样,就是四个脚本文件的打印输出,分别对应安装前后和卸载前后执行打印。所以用户可以在这四个脚本里面实现自己想要的功能。
分装多个包
上述配置是将所有需要打包的文件打包成一个安装包,但一个项目往往会有多个不同服务,在实施部署时需安装到不同的机子上,这个时候如果把所有服务一起打包,会导致部署时包太大。这个时候就需要用上 CPack 的 Components 功能。
下面介绍在这个过程需要用到的三个函数:cpack_add_component 和 cpack_add_component_group,还有 install。
以下为添加 install 的函数定义

以下为添加 component 的函数定义

以下为添加 group 的函数定义

以上述为例,假如我们要将 program A 和它的配置文件 A.conf 打成一个 rpm 包,将 program B 和它的配置文件 B.conf 打成一个 rpm 包,则需要在 CMakeLists.txt 里添加以下内容,把上述配置的 include(CPack) 移到下面配置的位置:
# 设置每个分组打包成一个 rpm 包
set(CPACK_COMPONENTS_GROUPING ONE_PER_GROUP)
# 设置支持 COMPONENT
set(CPACK_RPM_COMPONENT_INSTALL ON)
include(CPack)
# 添加一个名为 AComponent 的 component
cpack_add_component(AComponent
DISPLAY_NAME "A program"
DESCRIPTION "The program for test"
GROUP Aprogram)
# 添加一个名为 BComponent 的 component
cpack_add_component(BComponent
DISPLAY_NAME "B program"
DESCRIPTION "The program for test"
GROUP Bprogram)
# 添加一个名为 Aprogram 的 group, 这个名字会作为 rpm 包名字的一部分
cpack_add_component_group(Aprogram)
# 添加一个名为 Bprogram 的 group
cpack_add_component_group(Bprogram)
然后修改 src/CMakeLists.txt,看下图红框内容,将 program A 二进制文件配置为 AComponent,将 program B 二进制文件配置为 BComponent。

修改 etc/CMakeLists.txt,看下图红框内容,将配置文件 A.conf 配置为 AComponent, 将配置文件 B.conf 配置为 BComponent。

更新 CMakeLists.txt 的配置之后,重新执行下 cmake 命令生成新的 makefile 文件,并执行 cpack -G RPM,你可以在当前目录下面看到生成两个文件 example-1.0.0-Linux-Aprogram.rpm 和 example-1.0.0-Linux-Bprogram.rpm, 它们各自包含的文件如下:

其他常用参数
- 安装到指定目录:上述配置,生成的安装包只能安装到 /home/vesoft/install 目录,假如用户希望能够安装指定位置,这个时候需要在 include(CPack) 之前添加以下配置
# 将上述配置设置指定目录这个选项置为 OFF
set(CPACK_SET_DESTDIR OFF)
# 设置可重定目录的选择为 ON
set(CPACK_RPM_PACKAGE_RELOCATABLE ON)
# 设置默认重定的目录
set(CPACK_PACKAGING_INSTALL_PREFIX "/home/vesoft/install")
通过上述配置,重新生成的 rpm 包就可以支持安装到其他指定目录,下面是把它安装到 /home/test/install,使用如下:
sudo rpm -ivh example-1.0.0-Linux-Aprogram.rpm --prefix=/home/test/install
用户可以通过 CPACK_RPM_SPEC_MORE_DEFINE 这个参数在生成的 SEPC 文件里面增加相应的宏,来应用 rpmbuild 的一些功能开关。
更多…
CPack 有很多参数,不同版本参数有些差异,想要了解更多,可以去 CMake 官网查看,见 CPack。或直接通过 CPack --help 获取参数描述。
Nebula Graph 也是采用 CPack 进行打包成 rpm 和 deb 包,您可以通过 https://github.com/vesoft-inc/nebula/releases 获取到 Nebula Graph 每次 release 发布的包。

本文中如有任何错误或疏漏欢迎去 GitHub:https://github.com/vesoft-inc/nebula issue 区向我们提 issue 或者前往官方论坛:https://discuss.nebula-graph.com.cn/ 的 建议反馈 分类下提建议 ;加入 Nebula Graph 交流群,请联系 Nebula Graph 官方小助手微信号:NebulaGraphbot
作者有话说:Hi,我是 Laura,是图数据库 Nebula Graph 研发工程师,希望做的分享能给大家带来帮助,如有不当之处也希望能帮忙纠正,谢谢~
CPack 入门指南的更多相关文章
- Web API 入门指南 - 闲话安全
Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...
- Vue.js 入门指南之“前传”(含sublime text 3 配置)
题记:关注Vue.js 很久了,但就是没有动手写过一行代码,今天准备入手,却发现自己比菜鸟还菜,于是四方寻找大牛指点,才终于找到了入门的“入门”,就算是“入门指南”的“前传”吧.此文献给跟我一样“白痴 ...
- yii2实战教程之新手入门指南-简单博客管理系统
作者:白狼 出处:http://www.manks.top/document/easy_blog_manage_system.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文 ...
- 【翻译】Fluent NHibernate介绍和入门指南
英文原文地址:https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started 翻译原文地址:http://www.cnblogs ...
- ASP.NET MVC 5 入门指南汇总
经过前一段时间的翻译和编辑,我们陆续发出12篇ASP.NET MVC 5的入门文章.其中大部分翻译自ASP.NET MVC 5 官方教程,由于本系列文章言简意赅,篇幅适中,从一个web网站示例开始讲解 ...
- 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍
我们在前一篇文章微软新神器-Power BI,一个简单易用,还用得起的BI产品中,我们初步介绍了Power BI的基本知识.由于Power BI是去年开始微软新发布的一个产品,虽然已经可以企业级应用, ...
- 一起学微软Power BI系列-官方文档-入门指南(2)获取源数据
我们在文章: 一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍中,我们介绍了官方入门文档的第一章.今天继续给大家介绍官方文档中,如何获取数据源的相关内容.虽然是英文,但 ...
- 一起学微软Power BI系列-官方文档-入门指南(3)Power BI建模
我们前2篇文章:一起学微软Power BI系列-官方文档-入门指南(1)Power BI初步介绍 和一起学微软Power BI系列-官方文档-入门指南(2)获取源数据 中,我们介绍了官方入门文档与获取 ...
- 一起学微软Power BI系列-官方文档-入门指南(4)Power BI的可视化
在前面的系列文章中,我们介绍了官方有关获取数据,以及建模的原始文档和基本介绍.今天继续给大家介绍官方文档中,有关可视化的内容.实际上获获取数据和建模更注重业务关系的处理,而可视化则关注对数据的解读.这 ...
- 一起学微软Power BI系列-官方文档-入门指南(5)探索数据奥秘
我们几篇系列文章中,我们介绍了官方入门文档与获取数据等基本知识.今天继续给大家另外一个重点,探索数据奥秘.有了数据源,有了模型,下一步就是如何解析数据了.解析数据的过程需要很多综合技能,不仅仅是需要掌 ...
随机推荐
- python+selenium+opencv验证滑块
我们在使用selenium爬虫的时候在登录时经常会遇到滑块验证码问题,导致登录受阻,正所谓万事开头难. 登录就登录不进去更别提往后的操作的.今天以登录京东后台来演示下如何破解滑块. 一.登录 首先我们 ...
- 【行云流水线】满足你对工作流编排的一切幻想~skr
流水线模型 众所周知,DevOps流水线(DevOps pipeline)的本质是实现自动化工作流程,用于支持软件开发.测试和部署的连续集成.交付和部署(CI/CD)实践.它是DevOps方法论的核心 ...
- 隐私集合求交(PSI)协议研究综述
摘要 隐私集合求交(PSI)是安全多方计算(MPC)中的一种密码学技术,它允许参与计算的双方,在不获取对方额外信息(除交集外的其它信息)的基础上,计算出双方数据的交集.隐私集合求交在数据共享,广告转化 ...
- gin框架中如何实现流式下载
作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 团队中之前的文件下载做得比较复杂,因为担心量太大,是后台做 ...
- 主动学习(Active Learning)简介综述汇总以及主流技术方案
0.引言 在机器学习(Machine learning)领域,监督学习(Supervised learning).非监督学习(Unsupervised learning)以及半监督学习(Semi-su ...
- Python中局部放大图案例
例子一: 先上完整代码和效果图: import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1.ins ...
- 【STL源码剖析】vector类模拟实现 了解底层-走进底层-掌握底层【超详细的注释和解释】
今天博主继续带来STL源码剖析专栏的第二篇博客了! 今天带来vector的模拟实现! 其实在很多人学习C++过程中,都是只学习一些STL的使用方式,并不了解底层的实现.博主本人认为,这样的学习这样的技 ...
- P7167 [eJOI2020 Day1] Fountain 题解
题目链接:Fountain 很不错的基础算法组合题:单调栈+倍增 首先考虑到一个事实,就是下面第一个比当前半径大的位置会成为移动的第一次落脚点,抽象下就是下面出现的第一次比自身大的半径,这个问题显然可 ...
- FDMemTable用法
procedure TForm1.FormCreate(Sender: TObject); Var i:integer; begin // i:=15; self.FDMemTable1.FieldD ...
- Pandas—to_csv()写入函数参数详解
1. to_csv函数的参数 DataFrame.to_csv(path_or_buf=None, sep=',', na_rep='', float_format=None, columns=Non ...