CPack 入门指南

Stella981
• 阅读 642

CPack 入门指南

背景

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

CPack 在整个 CMake 工具链的位置。

CPack 入门指南

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.rpmexample-1.0.0-Linux.rpm 就是我们想要的安装包文件。

如果想要查看打包过程的详细输出,可以在命令后面添加 --verbose。CPack 是根据用户的配置生成_CPack_Packages/Linux/RPM/SPECS/example.spec 文件,然后让 rpm-build 用。

上面配置生成的安装包 example-1.0.0-Linux.rpm里面包含的文件如下:

CPack 入门指南

⚠️注意:假如安装时出现 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 命令会有以下输出

CPack 入门指南

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

CPack 入门指南

可以看到图片里面绿色和红色字样,就是四个脚本文件的打印输出,分别对应安装前后和卸载前后执行打印。所以用户可以在这四个脚本里面实现自己想要的功能。

分装多个包

上述配置是将所有需要打包的文件打包成一个安装包,但一个项目往往会有多个不同服务,在实施部署时需安装到不同的机子上,这个时候如果把所有服务一起打包,会导致部署时包太大。这个时候就需要用上 CPack 的 Components 功能。

下面介绍在这个过程需要用到的三个函数:cpack_add_componentcpack_add_component_group,还有 install

以下为添加 install 的函数定义

CPack 入门指南

以下为添加 component 的函数定义

CPack 入门指南

以下为添加 group 的函数定义

CPack 入门指南

以上述为例,假如我们要将 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。

CPack 入门指南

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

CPack 入门指南

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

CPack 入门指南

其他常用参数

  • 安装到指定目录:上述配置,生成的安装包只能安装到 /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 发布的包

CPack 入门指南

本文中如有任何错误或疏漏欢迎去 GitHub:https://github.com/vesoft-inc/nebula issue 区向我们提 issue 或者前往官方论坛:https://discuss.nebula-graph.com.cn/建议反馈 分类下提建议 👏;加入 Nebula Graph 交流群,请联系 Nebula Graph 官方小助手微信号:NebulaGraphbot

作者有话说:Hi,我是 Laura,是图数据库 Nebula Graph 研发工程师,希望做的分享能给大家带来帮助,如有不当之处也希望能帮忙纠正,谢谢~

点赞
收藏
评论区
推荐文章
blmius blmius
1年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
刚刚好 刚刚好
6个月前
css问题
1、在IOS中图片不显示(给图片加了圆角或者img没有父级)<div<imgsrc""/</divdiv{width:20px;height:20px;borderradius:20px;overflow:h
小森森 小森森
3天前
计划助手V1.0-微信小程序(QQ小程序)-源代码分享
疫情期间在家感觉好无聊啊,于是利用空闲时间做了一个用来记录和管理小目标时间的小程序,命名为《小沙漏》。QQ版本小程序同步上线,QQ小程序叫《时间小沙漏》,欢迎大家前来体验,后期也会添加其他的新功能哦【区别】:微信小程序的代码与QQ小程序的源码是不一样的。微信小程序的源码基于微信小程序云开发,需要在有网络的情况下使用,具有同步功能,所有记录在删除小
晴空闲云 晴空闲云
6个月前
css中box-sizing解放盒子实际宽高计算
我们知道传统的盒子模型,如果增加内边距padding和边框border,那么会撑大整个盒子,造成盒子的宽度不好计算,在实务中特别不方便。boxsizing可以设置盒模型的方式,可以很好的设置固定宽高的盒模型。盒子宽高计算假如我们设置如下盒子:宽度和高度均为200px,那么这会这个盒子实际的宽高就都是200px。但是当我们设置这个盒子的边框和内间距的时候,那
艾木酱 艾木酱
5个月前
快速入门|使用MemFire Cloud构建React Native应用程序
MemFireCloud是一款提供云数据库,用户可以创建云数据库,并对数据库进行管理,还可以对数据库进行备份操作。它还提供后端即服务,用户可以在1分钟内新建一个应用,使用自动生成的API和SDK,访问云数据库、对象存储、用户认证与授权等功能,可专
Wesley13 Wesley13
1年前
MySQL查询按照指定规则排序
1.按照指定(单个)字段排序selectfromtable_nameorderiddesc;2.按照指定(多个)字段排序selectfromtable_nameorderiddesc,statusdesc;3.按照指定字段和规则排序selec
Stella981 Stella981
1年前
Angular material mat
IconIconNamematiconcode_add\_comment_addcommenticon<maticonadd\_comment</maticon_attach\_file_attachfileicon<maticonattach\_file</maticon_attach\
Wesley13 Wesley13
1年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
NVIDIA安培架构下MIG技术分析
关键词:NVIDIA、MIG、安培一什么是MIG2020年5月,NVIDIA发布了最新的GPU架构:安培,以及基于安培架构的最新的GPU:A100。安培提供了许多新的特性,MIG是其中一项非常重要的新特性。MIG的全名是MultiInstanceGPU。NVIDIA安培架构中的MIG模式可以在A100GPU上并行运行七个作业。多实
helloworld_28799839 helloworld_28799839
6个月前
常用知识整理
Javascript判断对象是否为空jsObject.keys(myObject).length0经常使用的三元运算我们经常遇到处理表格列状态字段如status的时候可以用到vue
helloworld_34035044 helloworld_34035044
8个月前
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为