概述

RPM(Redhat Package Manager)是用于Redhat、CentOS、Fedora等Linux 分发版(distribution)的常见的软件包管理器。因为它允许分发已编译的软件,所以用户只用一个命令就可以安装软件。

准备

首先请准备一个Linux环境,比如CentOS。
RPM打包使用的是rpmbuild命令,这个命令来自rpm-build包,这个是必装的。

yum install rpm-build

当然也可以直接安装rpmdevtools,这个工具还包含一些其他的工具,同时它依赖rpm-build,所以直接安装的话会同时把rpm-build装上。

yum install rpmdevtools

当然,根据不同的软件构建过程,还需要其他的编译打包工具,比如C语言的make、gcc,python的setuptools等,根据需要安装即可。

原理

RPM打包的时候需要编译源码,还需要把编译好的配置文件、二进制命令文件之类的东西按照安装好的样子放到合适的位置,还要根据需要对RPM的包进行测试,这些都需要先有一个“工作空间”。rpmbuild命令使用一套标准化的“工作空间”:
生成 rpmbuild 目录

rpmdev-setuptree

rpmdev-setuptree这个命令就是安装rpmdevtools带来的。可以看到运行了这个命令之后,在$HOME家目录下多了一个叫做rpmbuild的文件夹,里边内容如下:

$ tree rpmbuild
rpmbuild
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

如果没有安装rpmdevtools的话,其实用mkdir命令创建这些文件夹也是可以的。

mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

从这些文件的名字大体也能看得出来都是干嘛用的。具体来说:

默认位置

宏代码

名 称

用途

~/rpmbuild/SPECS

%_specdir

Spec 文件目录

保存 RPM 包配置(.spec)文件

~/rpmbuild/SOURCES

%_sourcedir

源代码目录

保存源码包(如 .tar 包)和所有 patch 补丁

~/rpmbuild/BUILD

%_builddir

构建目录

源码包被解压至此,并在该目录的子目录完成编译

~/rpmbuild/BUILDROOT

%_buildrootdir

最终安装目录

保存 %install 阶段安装的文件

~/rpmbuild/RPMS

%_rpmdir

标准 RPM 包目录

生成/保存二进制 RPM 包

~/rpmbuild/SRPMS

%_srcrpmdir

源代码 RPM 包目录

生成/保存源码 RPM 包(SRPM)

说明

SPEC关键字

**Name: **软件包的名称,后面可使用%{name}的方式引用

**Summary: **软件包的内容概要

**Version: **软件的实际版本号,例如:1.0.1等,后面可使用%{version}引用

Release: 发布序列号,例如:1linuxing等,标明第几次打包,后面可使用%{release}引用

**Group: **软件分组,建议使用标准分组

**License: **软件授权方式,通常就是GPL

**Source: **源代码包,可以带多个用Source1、Source2等源,后面也可以用%{source1}、%{source2}引用

**BuildRoot: **这个是安装或编译时使用的“虚拟目录”,考虑到多用户的环境,一般定义为:%{tmppath}/{name}-%{version}-%{release}-root或%{tmppath}/%{name}-%{version}-%{release}-buildroot-%%__id_u} -n}.该参数非常重要,因为在生成rpm的过程中,执行make install时就会把软件安装到上述的路径中,在打包的时候,同样依赖“虚拟目录”为“根目录”进行操作。后面可使用$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包所依赖的软件包名称,可以用>=或<=表示大于或小于某一特定版本,例如:libpng-devel >= 1.0.20 zlib ※“>=”号两边需用空格隔开,而不同软件名称也用空格分开,还有例如PreReq、Requires(pre)、Requires(post)、Requires(preun)、Requires(postun)、BuildRequires等都是针对不同阶段的依赖指定

BuildRequires 编译时的依赖

**Provides: **指明本软件一些特定的功能,以便其他rpm识别

**Packager: **打包者的信息

**%description **软件的详细说明

SPEC脚本主体

%prep 预处理脚本

%setup %setup -q 解压并cd到相关目录
%setup -n %{name}-%{version} 把源码包解压并放好通常是从/usr/src/asianux/SOURCES里的包解压到/usr/src/asianux/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 将所有打补丁时产生的输出文件删除。
%configure 这个不是关键字,而是rpm定义的标准宏命令。意思是执行源代码的configure配置,在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行 ,使用标准写法,会引用/usr/lib/rpm/marcros中定义的参数。另一种不标准的写法是,可参考源码中的参数自定义,例如:
引用CFLAGS=“制作zabbix的rpm包 rpm包制作原理_linuxRPM_OPT_FLAGS” ./configure --prefix=%{_prefix}

**%build **开始构建包,在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make的工作

**%install **开始把软件安装到虚拟的根目录中.在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make install的操作。这个很重要,因为如果这里的路径不对的话,则下面%file中寻找文件的时候就会失败。 常见内容有:

**%makeinstall **这不是关键字,而是rpm定义的标准宏命令。也可以使用非标准写法:make DESTDIR=制作zabbix的rpm包 rpm包制作原理_源码包_02RPM_BUILD_ROOT install

需要说明的是,这里的%install主要就是为了后面的%file服务的。所以,还可以使用常规的系统命令:引用install -d $RPM_BUILD_ROOT/和cp -a * $RPM_BUILD_ROOT/

%clean 清理临时文件

%pre rpm安装前执行的脚本

%post rpm安装后执行的脚本

%preun rpm卸载前执行的脚本

%postun rpm卸载后执行的脚本

%files 定义那些文件或目录会放入rpm中

**%defattr (-,root,root) **指定包装文件的属性,分别是(mode,owner,group),-表示默认值,对文本文件是0644,可执行文件是0755
%defattr 用于设置默认文件权限,通常可以在 %files 的开头看到它。注意,如果不需要修改权限,则不需要使用它。其格式为:

%defattr(<文件权限>, <用户>, <用户组>, <目录权限>)

**%changelog ** 变更日志,标签应包含每个 Release 所做的更改日志,尤其应包含上游的安全/漏洞补丁的说明。Changelog 日志可使用 rpm --changelog -q 查询,通过查询可得知已安装的软件是否包含指定漏洞和安全补丁。%changelog 条应包含版本字符串,以避免 rpmlint 工具警告。

命令及工具

rpmbuild打包

一旦 SPEC 编写完毕,请执行以下命令来构建 SRPM 和 RPM 包:

rpmbuild -ba program.spec

如果成功,RPM 会保存至 ~/rpmbuild/RPMS,SRPM 会保存至 ~/rpmbuild/SRPMS。

如果失败,请查看 BUILD 目录的相应编译日志。为了帮助调试,可以用 --short-circuit 选项来忽略成功的阶段。例如,若想要(略过更早的阶段)重新从 %install 阶段开始,请执行:

rpmbuild -bi --short-circuit program.spec

如果只想创建 RPM,请执行:

rpmbuild -bb program.spec

如果只想创建 SRPM(不需要执行 %prep 或 %build 或其他阶段),请执行:

rpmbuild -bs program.spec

rpmlint检查

为避免常见错误,请先使用 rpmlint 查找 SPEC 文件的错误:

rpmlint program.spec

如果返回错误/警告,使用 “-i” 选项查看更详细的信息。

也可以使用 rpmlint 测试已构建的 RPM 包,检查 SPEC/RPM/SRPM 是否存在错误。你需要在发布软件包之前,解决这些警告。此页面 提供一些常见问题的解释。如果你位于 SPEC 目录中,请执行:

rpmlint NAME.spec …/RPMS//NAME.rpm …/SRPMS/NAME*.rpm

进入 ~/rpmbuild/RPMS 下的特定架构目录中,您会发现有许多二进制 RPM 包。使用以下命令快速查看 RPM 包含的文件和权限:

rpmls *.rpm

rpm安装

如果看上去正常,以 root 身份安装它们:

rpm -ivp package1.rpm package2.rpm package3.rpm …

以不同方式来测试程序,看看是否全部都正常工作。如果是 GUI 工具,请确认其是否出现在桌面菜单中,否则表示 .desktop 条目可能有错。
最后卸载软件包:

rpm -e package1 package2 package3

附录

rpmbuild目录

默认位置

宏代码

名称

用途

~/rpmbuild/SPECS

%_specdir

Spec 文件目录

保存 RPM 包配置(.spec)文件

~/rpmbuild/SOURCES

%_sourcedir

源代码目录

保存源码包(如 .tar 包)和所有 patch 补丁

~/rpmbuild/BUILD

%_builddir

构建目录

源码包被解压至此,

~/rpmbuild/BUILDROOT

%_buildrootdir

最终安装目录

保存 %install 阶段安装的文件

~/rpmbuild/RPMS

%_rpmdir

标准 RPM 包目录

生成/保存二进制 RPM 包

~/rpmbuild/SRPMS

%_srcrpmdir

源代码 RPM 包目录

生成/保存源码 RPM 包(SRP

spec文件阶段

阶段

读取的目录

写入的目录

具体动作

%prep

%_sourcedir

%_builddir

读取位于 %_sourcedir 目录的源代码和 patch 。之后,解压源代码至 %_builddir 的子目录并应用所有 patch。

%build

%_builddir

%_builddir

编译位于 %_builddir 构建目录下的文件。通过执行类似 ./configure && make 的命令实现。

%install

%_builddir

%_buildrootdir

读取位于 %_builddir 构建目录下的文件并将其安装至 %_buildrootdir 目录。这些文件就是用户安装 RPM 后,最终得到的文件。注意一个奇怪的地方: 最终安装目录 不是 构建目录。通过执行类似 make install 的命令实现。

%check

%_builddir

%_builddir

检查软件是否正常运行。通过执行类似 make test 的命令实现。很多软件包都不需要此步。

bin

%_buildrootdir

%_rpmdir

读取位于 %_buildrootdir 最终安装目录下的文件,以便最终在 %_rpmdir 目录下创建 RPM 包。在该目录下,不同架构的 RPM 包会分别保存至不同子目录, noarch 目录保存适用于所有架构的 RPM 包。这些 RPM 文件就是用户最终安装的 RPM 包。

src

%_sourcedir

%_srcrpmdir

创建源码 RPM 包(简称 SRPM,以.src.rpm 作为后缀名),并保存至 %_srcrpmdir 目录。SRPM 包通常用于审核和升级软件包。

file代表路径的宏列表
%{_sysconfdir}        /etc
%{_prefix}            /usr
%{_exec_prefix}       %{_prefix}
%{_bindir}            %{_exec_prefix}/bin
%{_libdir}            %{_exec_prefix}/%{_lib}
%{_libexecdir}        %{_exec_prefix}/libexec
%{_sbindir}           %{_exec_prefix}/sbin
%{_sharedstatedir}    /var/lib
%{_datarootdir}       %{_prefix}/share
%{_datadir}           %{_datarootdir}
%{_includedir}        %{_prefix}/include
%{_infodir}           /usr/share/info
%{_mandir}            /usr/share/man
%{_localstatedir}     /var
%{_initddir}          %{_sysconfdir}/rc.d/init.d
%{_var}               /var
%{_tmppath}           %{_var}/tmp
%{_usr}               /usr
%{_usrsrc}            %{_usr}/src
%{_lib}               lib (lib64 on 64bit multilib systems)
%{_docdir}            %{_datadir}/doc
%{buildroot}          %{_buildrootdir}/%{name}-%{version}-%{release}.%{_arch}
$RPM_BUILD_ROOT       %{buildroot}