CentOS下 rpm 包制作
RPM(Red Hat Package Manager)是用于 Linux 分发版(distribution)的最常见的软件包管理器。因为它允许分发已编译的软件,所以用户只用一个命令就可以安装软件。RPM 是 Linux“标准基本库”版本 1.0.0 指定的安装工具。在 Linux 分发版前 10 名中,有 8 个是基于 RPM(请参阅“Comparison of Linux Distributions”)。即使某些通常不使用 RPM 的分发版,如 Debian,也有可用工具将 RPM 转换成它们自己的格式。在 Linux 上,对于除开发人员以外的任何人,RPM 也是用来打包软件的最佳选择。本文通过一个webhook,介绍rpm软件包的制作
使用centos7
准备环境
1 | git clone https://github.com/XiaoMi/soar.git | 
从spec文档建立有以下选项:
1 | -bp                     #只执行spec的%pre 段(解开源码包并打补丁,即只做准备) | 
2 | -bc                              #执行spec的%pre和%build 段(准备并编译) | 
3 | -bi                               #执行spec中%pre,%build与%install(准备,编译并安装) | 
4 | -bl                               #检查spec中的%file段(查看文件是否齐全) | 
5 | -ba                              #建立源码与二进制包(常用) | 
6 | -bb                              #只建立二进制包(常用) | 
7 | -bs                              #只建立源码包 | 
1. 配置工作目录
安装构建工具
1 | yum install rpmdevtools wget tree | 
使用命令生成工作目录
1 | rpmdev-setuptree | 
rpmdev-setuptree 命令默认将再当前用户主目录下创建一个RPM构建根目录结构,
如果需要改变次默认位置,可以修改配置文件:~/.rpmmacros中变量 _topdir 对应
的值即可。 
生成的目录如下
1 | rpmbuild/ | 
2 | ├── BUILD     # BUILD 打包过程中的工作目录 | 
3 | ├── RPMS      # 存放生成的二进制包 | 
4 | ├── SOURCES   # 放置打包资源,包括源码打包文件和补丁文件 | 
5 | ├── SPECS     # SPECS 目录放置 SPEC 文档 | 
6 | └── SRPMS     # 目录存放生成的源码包 | 
BUILDROOT 是制作过程中临时安装程序的地方
2. 制作过程概览
为了构建 RPM 软件包,您需要写一个名为 spec 文件的 RPM 输入文件,该文件告诉 RPM 如何构建和打包您的软件。编写 spec 文件您需要:
如果您首次创建 .spec 文件,vim 或 emacs 会自动生成模板:
1 | Name: | 
2 | Version: | 
3 | Release:	1%{?dist} | 
4 | Summary: | 
5 | Group: | 
6 | License: | 
7 | URL: | 
8 | Source0: | 
9 | BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) | 
10 | |
11 | BuildRequires: | 
12 | Requires: | 
13 | |
14 | %description | 
15 | |
16 | %prep | 
17 | %setup -q | 
18 | |
19 | %build | 
20 | %configure | 
21 | make %{?_smp_mflags} | 
22 | |
23 | %install | 
24 | rm -rf %{buildroot} | 
25 | make install DESTDIR=%{buildroot} | 
26 | |
27 | %clean | 
28 | rm -rf %{buildroot} | 
29 | |
30 | %files | 
31 | %defattr(-,root,root,-) | 
32 | %doc | 
33 | |
34 | %changelog | 
您可以使用 $RPM_BUILD_ROOT 代替 %{buildroot},两者都可以使用。
spec文档的内容
1 | Name: 软件包的名称,后面可使用%{name}的方式引用,具体命令需跟源包一致 | 
2 | Summary:                    软件包的内容概要 | 
3 | Version:                        软件的实际版本号,具体命令需跟源包一致 | 
4 | Release:                        发布序列号,具体命令需跟源包一致 | 
5 | Group:                          软件分组,建议使用标准分组 | 
软件包所属类别,具体类别有:
Amusements/Games                                (娱乐/游戏)
Amusements/Graphics                              (娱乐/图形)
Applications/Archiving                               (应用/文档)
Applications/Communications                 (应用/通讯)
Applications/Databases                              (应用/数据库)
Applications/Editors                                   (应用/编辑器)
Applications/Emulators                             (应用/仿真器)
Applications/Engineering                         (应用/工程)
Applications/File                                         (应用/文件)
Applications/Internet                                (应用/因特网)
Applications/Multimedia                          (应用/多媒体)
Applications/Productivity                        (应用/产品)
Applications/Publishing                           (应用/印刷)
Applications/System                                 (应用/系统)
Applications/Text                                      (应用/文本)
Development/Debuggers                         (开发/调试器)
Development/Languages                          (开发/语言)
Development/Libraries                             (开发/函数库)
Development/System                                 (开发/系统)
Development/Tools                                     (开发/工具)
Documentation                                           (文档)
System Environment/Base                        (系统环境/基础)
System Environment/Daemons                (系统环境/守护)
System Environment/Kernel                     (系统环境/内核)
System Environment/Libraries                (系统环境/函数库)
System Environment/Shells                      (系统环境/接口)
User Interface/Desktops                             (用户界面/桌面)
User Interface/X                                          (用户界面/X窗口)
User Interface/X Hardware Support        (用户界面/X硬件支持)
License: 软件授权方式,通常就是GPL
1 | Source: 源代码包,可以带多个用Source1、Source2等源,后面也可以用%{source1}、%{source2}引用 | 
2 | BuildRoot: 这个是安装或编译时使用的“虚拟目录”,考虑到多用户的环境,一般定义为: | 
3 | %{_tmppath}/%{name}-%{version}-%{release}-root 或 %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n} | 
4 | 该参数非常重要,因为在生成[rpm](https://www.fooher.com/tag/rpm)的过程中,执行make install时就会把软件安装到上述的路径中,在打包的时候,同样依赖“虚拟目录”为“根目录”进行操作。 | 
5 | 后面可使用$RPM_BUILD_ROOT 方式引用。 | 
URL: 软件的主页
Vendor: 发行商或打包组织的信息,例如RedFlag Co,Ltd
Disstribution: 发行版标识
Patch: 补丁源码,可使用Patch1、Patch2等标识多个补丁,使用%patch0或%{patch0}引用
Prefix: %{_prefix} 这个主要是为了解决今后安装rpm包时,并不一定把软件安装到rpm中打包的目录的情况。这样,必须在这里定义该标识,并在编写%install脚本的时候引用,才能实现rpm安装时重新指定位置的功能
Prefix: %{_sysconfdir} 这个原因和上面的一样,但由于%{_prefix}指/usr,而对于其他的文件,例如/etc下的配置文件,则需要用%{_sysconfdir}标识
Build Arch: 指编译的目标处理器架构,noarch标识不指定,但通常都是以/usr/lib/rpm/marcros中的内容为默认值
Requires: 该rpm包所依赖的软件包名称,可以用>=或<=表示大于或小于某一特定版本,
spec脚本主体
spec脚本的主体中也包括了很多关键字和描述,下面会一一列举。我会把一些特别需要留意的地方标注出来。
%prep 预处理脚本
%setup -n %{name}-%{version} 把源码包解压并放好
注:可根据你的源码的名字格式,来确认解压后名字的格式,否则可能导致install的时候找不到对应的目录
通常是从/usr/src/redhat/SOURCES里的包解压到/usr/src/redhat/BUILD/%{name}-%{version}中。
一般用%setup -c就可以了,但有两种情况:一就是同时编译多个源码包,二就是源码的tar包的名称与解压出来的目录不一致,此时,就需要使用-n参数指定一下了。
%patch 打补丁
通常补丁都会一起在源码tar.gz包中,或放到SOURCES目录下。一般参数为:
%patch -p1 使用前面定义的Patch补丁进行,-p1是忽略patch的第一层目录
%Patch2 -p1 -b xxx.patch 打上指定的补丁,-b是指生成备份文件
◎补充一下
%setup 不加任何选项,仅将软件包打开。
%setup -n newdir 将软件包解压在newdir目录。
%setup -c 解压缩之前先产生目录。
%setup -b num 将第num个source文件解压缩。
%setup -T 不使用default的解压缩操作。
%setup -T -b 0 将第0个源代码文件解压缩。
%setup -c -n newdir 指定目录名称newdir,并在此目录产生rpm套件。
%patch 最简单的补丁方式,自动指定patch level。
%patch 0 使用第0个补丁文件,相当于%patch ?p 0。
%patch -s 不显示打补丁时的信息。
%patch -T 将所有打补丁时产生的输出文件删除。
预处理 %prep:
预处理通常用来执行一些解开源程序包的命令,为下一步的编译安装做准备。
%prep 和下面的 %build,%install 段一样,除了可以执行 RPM 所定义的
宏命令(以 % 开头)以外,还可以执行 SHELL 命令,功能类似 ./configure
作用:
用来准备要编译的软件。通常,这一段落将归档中的源代码解压,并应用补丁。
这些可以用标准的 Shell 命令完成,但是更多地使用预定义的宏.
检查标签语法是否正确,删除旧的软件源程序,对包含源程序的 tar 文件进行解码。
如果包含补丁(patch)文件,将补丁文件应用到解开的源码中。它一般包含 %setup
与 %patch 两个命令。%setup 用于将软件包打开,执行 %patch 可将补丁文件加入
解开的源程序中.
%prep
宏 %setup
该宏解开源代码,将当前目录改为源代码解压之后产生的目录。这个宏还有一些选项
可以使用,如,在解压后, %setup 宏假设产生的目录是 %{name}-%{version}
如果 tar 打包中的目录不是这样命名的,可以用 -n 选项来指定要切换到的目录。
如:%setup -n%{name}-April2003Rel
还有如下其他参数:
%setup -q   — 将 tar 命令的繁复输出关闭
%setup -nnewdir  — 将压缩的软件源程序在 newdir 目录下解开
%setup -c  — 在解开源程序之前先创建目录
%setup -bnum  — 在包含多个源程序时,将第 num 个源程序解压缩
%setup -T   — 不使用缺省的解压缩操作
%files 基础
%defattr 用于设置默认文件权限,通常可以在 %files 的开头看到它。注意,如果不需要修改权限,则不需要使用它。其格式为:
1 | %defattr(<文件权限>, <用户>, <用户组>, <目录权限>) | 
第 4 个参数通常会省略。常规用法为 %defattr(-,root,root,-),其中 “-“ 表示默认权限。
您应该列出该软件包拥有的所有文件和目录。尽量使用宏代替目录名,查看宏列表 Packaging:RPMMacros(例如:使用 %{_bindir}/mycommand 代替 /usr/bin/mycommand)。如果路径以 “/“ 开头(或从宏扩展),则从 %{buildroot} 目录取用。否则,假设文件在当前目录中(例如:在 %{_builddir} 中,包含需要的文档)。如果您的包仅安装一个文件,如 /usr/sbin/mycommand,则 %files 部分如下所示:
1 | %files | 
2 | %{_sbindir}/mycommand | 
若要使软件包不受上游改动的影响,可使用通配符匹配所有文件:
1 | %{_bindir}/* | 
包含一个目录:
1 | %{_datadir}/%{name}/ | 
注意,%{_bindir}/* 不会声明此软件包拥有 /usr/bin 目录,而只包含其中的文件。如果您列出一个目录,则该软件包拥有这个目录,及该目录内的所有文件和子目录。因此,不要列出 %{_bindir},并且要小心的处理那些可能和其他软件包共享的目录。
如果存在以下情况,可能引发错误:
- 通配符未匹配到任何文件或目录
 - 文件或目录被多次列出
 - 未列出 
%{buildroot}下的某个文件或目录 - 您也可以使用 
%exclude来排除文件。这对于使用通配符来列出全部文件时会很有用,注意如果未匹配到任何文件也会造成失败。 
您可能需要在 %files 部分添加一个或多个前缀;请用空格分隔。详情请查看 Max RPM section on %files directives。
通常,”%doc“ 用于列出 %{_builddir} 内,但未复制到 %{buildroot} 中的文档。通常包括 README 和 INSTALL。它们会保存至 /usr/share/doc 下适当的目录中,不需要声明 /usr/share/doc 的所有权。
注意: 如果指定 %doc 条目,rpmbuild < 4.9.1 在安装前会将 %doc 目录删除。这表明已保存至其中的文档,例如,在 %install 中安装的文档会被删除,因此最终不会出现在软件包中。如果您想要在 %install 中安装一些文档,请将它们临时安装到 build 目录(不是 build root 目录)中,例如 _docs_staging,接着在 %files 中列出,如 %doc _docs_staging/* 这样。
配置文件保存在 /etc 中,一般会这样指定(确保用户的修改不会在更新时被覆盖):
1 | %config(noreplace) %{_sysconfdir}/foo.conf | 
如果更新的配置文件无法与之前的配置兼容,则应这样指定:
1 | %config %{_sysconfdir}/foo.conf | 
“%attr(mode, user, group)“ 用于对文件进行更精细的权限控制,”-“ 表示使用默认值:
1 | %attr(0644, root, root) FOO.BAR | 
“%caps(capabilities)“ 用于为文件分配 POSIX capabilities。例如:
1 | %caps(cap_net_admin=pe) FOO.BAR | 
如果包含特定语言编写的文件,请使用 %lang 来标注:
1 | %lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh* | 
使用区域语言(Locale)文件的程序应遵循 处理 i18n 文件的建议方法:
- 在 
%install步骤中找出文件名:%find_lang ${name} - 添加必要的编译依赖: 
BuildRequires: gettext - 使用找到的文件名: 
%files -f ${name}.lang 
以下前缀在 Fedora 中无效:%license 和 %readme。
常用的宏
1 | RPM_BUILD_DIR:          /usr/src/redhat/BUILD | 
2 | RPM_BUILD_ROOT:         /usr/src/redhat/BUILDROOT | 
3 | %{_sysconfdir}:         /etc | 
4 | %{_sbindir}:           /usr/sbin | 
5 | %{_bindir}:             /usr/bin | 
6 | %{_datadir}:            /usr/share | 
7 | %{_mandir}:             /usr/share/man | 
8 | %{_libdir}:             /usr/lib64 | 
9 | %{_prefix}:             /usr | 
10 | %{_localstatedir}:      /usr/var | 
11 | %{_unitdir}             /usr/lib/systemd/system/ | 
%{_bindir} | 
/usr/bin | 
二进制目录:保存可执行文件 | 
|---|---|---|
%{_builddir} | 
~/rpmbuild/BUILD | 
构建目录:软件在 build 的子目录被编译。参考 %buildsubdir | 
%{buildroot} | 
~/rpmbuild/BUILDROOT | 
Build root:%install 阶段中,将 %{_builddir} 子目录下的文件复制到 %{buildroot} 的子目录(之前,%{buildroot}使用的位置为 “/var/tmp/“) | 
%{buildsubdir} | 
%{_builddir}/%{name} | 
构建子目录:%build 阶段中,文件会在 %{_builddir} 的子目录中编译。此宏在 %autosetup 之后设置 | 
%{_datadir} | 
/usr/share | 
共享数据目录 | 
%{_defaultdocdir} | 
/usr/share/doc | 
默认文档目录 | 
%{dist} | 
.fc*NUMBER* | 
发行版名称+版本号(例如 “.fc30“) | 
%{fedora} | 
*NUMBER* | 
Fedora 发行版本号(例如 “30“) | 
%{_includedir} | 
/usr/include | 
程序头文件目录 | 
%{_infodir} | 
/usr/share/info | 
info 手册目录 | 
%{_initrddir} | 
/etc/rc.d/init.d | 
init 脚本目录 | 
%{_libdir} | 
/usr/lib | 
共享库目录 | 
%{_libexecdir} | 
/usr/libexec | 
仅由系统调用执行该目录中的命令 | 
%{_localstatedir} | 
/var | 
保存缓存/日志/lock等信息的目录 | 
%{_mandir} | 
/usr/share/man | 
man 手册目录 | 
%{name} | 
软件包名称,通过 Name: tag 设置 | |
%{_sbindir} | 
/usr/sbin | 
保存管理员可执行命令 | 
%{_sharedstatedir} | 
/var/lib | 
保存程序运行所处理的文件 | 
%{_sysconfdir} | 
/etc | 
配置文件目录 | 
%{version} | 
软件包版本,通过 Version: tag 设置 | 
您可以查看 /etc/rpm/* 和 /usr/lib/rpm,以及 /usr/lib/rpm/macros 以进一步了解宏。或使用 rpm --showrc 显示当前 RPM 所使用的宏变量和值(根据 rpmrc 和宏)
1 | %define debug_package %{nil} | 
2 | Name: webhooks | 
3 | Version: 0.1.1 | 
4 | Release:	1%{?dist} | 
5 | Summary: a git sync tools | 
6 | |
7 | Group:  Development/Tools | 
8 | License: GPL | 
9 | URL: http://www.github.com/becivells/go-webhook | 
10 | Source0: %{name}-%{version}.tar.gz | 
11 | Source1: webhooks.service | 
12 | |
13 | BuildRoot: %{_tmppath}/%{name}-%{main_version}-%{main_release}-root | 
14 | %description | 
15 | a git tool for repo to webroot | 
16 | |
17 | %prep | 
18 | %setup -q | 
19 | |
20 | %build | 
21 | go build -o webhooks | 
22 | |
23 | %install | 
24 | %{__rm} -rf $RPM_BUILD_ROOT | 
25 | %{__mkdir} -p $RPM_BUILD_ROOT/usr/lib/systemd/system/ | 
26 | %{__mkdir} -p $RPM_BUILD_ROOT/opt/webhooks | 
27 | %{__install} -m755  webhooks $RPM_BUILD_ROOT/opt/webhooks/webhooks | 
28 | %{__install}  webhooks.yaml $RPM_BUILD_ROOT/opt/webhooks/webhooks.yaml | 
29 | %{__install} -m644  %SOURCE1  $RPM_BUILD_ROOT/%{_unitdir}/webhooks.service | 
30 | |
31 | %files | 
32 | %defattr(-,root,root,-) | 
33 | /opt/webhooks/ | 
34 | /usr/lib/systemd/system/ | 
35 | %clean | 
36 | %{__rm} -rf $RPM_BUILD_ROOT | 
https://github.com/Becivells/linux-package
https://www.cnblogs.com/jimodetiantang/p/9573098.html
https://www.fooher.com/20180112_155.html
https://fedoraproject.org/wiki/How_to_create_an_RPM_package/zh-cn