RPM打包指南


发布于 2021-02-06 / 41 阅读 / 0 评论 /
rpm全称redhat package manager,原本是 Red Hat Linux 发行版专门用来管理 Linux 各项套件的程序,由于它遵循 GPL 规则且功能强大方便

1.rpm概述

内容基本源自https://rpm-packaging-guide.github.io/。

1.1.为什么需要 RPM 来打包呢

RPM 是运行在 Redhat CentOS 和 Fedora 上的包管理系统。RPM 帮助你更简单的分发,管理和更新软件。很多软件供应商通过传统的压缩包来分发软件。将软件打包到 RPM 中有以下几个优点:

RPM可以安装,重新安装,删除,升级和验证包:用户可以使用标准的包管理工具(例如 Yum 或者 PackageKit)来安装,重新安装,移除升级和验证你的 RPM 包。

使用已安装软件包的数据库来查询和验证已安装软件包:因为 RPM 维护已安装软件包及其文件的数据库,因此用户可以轻松查询和验证其系统上的软件包。

使用元数据来描述包,安装说明等:每个 RPM 软件包都包含描述软件包组件,版本,发行版,大小,项目 url,安装说明等的元数据。

将原始软件打包为源包和二进制包:RPM允许您获取原始软件源并将其打包为用户的源和二进制包。 在源包中,您拥有原始源以及所使用的任何修补程序以及完整的构建说明。 随着软件的新版本发布,此设计可以简化软件包的维护。

将包添加到 Yum 仓库:你可以将软件包添加到 yum 仓库,是客户端可以轻松查找和部署软件。

对包进行数字签名:使用 GPG 签名秘钥,你可以对包进行数字签名,以便用户能够验证包的真实性

1.2.rpm依赖工具

如果要使用rpm打包,我们需要预先安装一些rpm的依赖工具。例如gcc、rpm-build、rpm-devel、rpmlint、make、python、bash、coreutils、diffutils、patch、rpmdevtools等。在Fedora、CentOS8和RHEL8中通过“dnf install ${softwares}”进行安装,而CentOS7和RHEL7则通过“yum install ${softwares}”进行安装。

1.3.rpmbuild打包目录

rpm打包目录有一些严格的层次上的要求。

rpm的版本<=4.4.x,rpmbuid工具其默认的工作路径是 /usr/src/redhat因为权限的问题,普通用户不能制作rpm包,制作rpm软件包时必须切换到 root 身份才可以。

rpm从4.5.x版本开始,将rpmbuid的默认工作路径移动到用户家目录下的rpmbuild目录里,即 $HOME/rpmbuild ,并且推荐用户在制作rpm软件包时尽量不要以root身份进行操作。

rpmbuild默认工作路径的确定,通常由在/usr/lib/rpm/macros这个文件里的一个叫做 %_topdir 的宏变量来定义。在%_topdir目录下一般需要建立6个目录,如下表所示:

目录

宏代码

名称

作用

SPECS

%_specdir

Spec 文件目录

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

SOURCES

%_sourcedir

源代码目录

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

BUILD

%_builddir

构建目录

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

BUILDROOT

%_buildrootdir

最终安装目录

保存 %install 阶段安装的文件

RPMS

%_rpmdir

标准 RPM 包目录

生成/保存二进制 RPM 包

SRPMS

%_srcrpmdir

源代码 RPM 包目录

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

在构建rpm包之前,最好清理一下SOURCES目录。

1.4.SPEC文件说明

spec文件就是软件包描述文件。这个文件中包含了软件包的诸多信息,如:软件包的名字、版本、类别、说明摘要、创建时要执行什么指令、安装时要执行什么操作、以及软件包所要包含的文件列表等等。

spec文件内容由两部分组成:文件头和内容体。

1.4.1.spec文件头信息

涉及的条目如下表所示:

SPEC文件头指令

说明

Name

Name 软件包的名字,最终 rpm 软件包是用该名字与版本号(Version)、释出号(Release)及体系号来命名软件包的,后面可使用 %{name} 的方式引用,与SPEC文件名匹配

Version

软件版本号。仅当软件包比以前有较大改变时才增加版本号,后面可使用%{version}引用

Release

软件包释出号/发行号。一般我们对该软件包做了一些小的补丁的时候就应该把释出号加 1,后面可使用 %{release} 引用

Summary

用一句话概括该软件包尽量多的信息

License

软件授权方式,通常是GPL(自由软件)或GPLv2,BSD

URL

软件的主页

Source0

Source0 源程序软件包的名字/源代码包的名字,如 stardict-2.0.tar.gz。可以带多个用 Source1、Source2 等源,后面也可以用 %{source1}、%{source2} 引用

Patch0

用于源码的第一个补丁

BuildArch

指编译的目标处理器架构,noarch 标识不指定,但通常都是以 /usr/lib/rpm/marcros 中的内容为默认值

BuildRequires

制作过程中用到的软件包,构建依赖

Requires

安装时所需软件包,可以通过“Requires(pre)”指定不同阶段的依赖

ExcludeArch

如果软件不能运行在某处理器框架下,则在此指定。

每条指令占一行内容。

1.4.2.spec文件内容

文件内容主要包含下表中的指令。

SPEC指令

描述

%description

软件包详细说明,可写在多个行上。

%prep

预处理通常用来执行一些解开源程序包的命令,为下一步的编译安装作准备。%prep和下面的%build,%install段一样,除了可以执行RPM所定义的宏命令(以%开头)以外,还可以执行SHELL命令。功能上类似于./configure。

%setup

这个宏解压源代码,将当前目录改为源代码解压之后产生的目录。这个宏还有一些选项可以用。例如,在解压后,%setup 宏假设产生的目录是%{name}-%{version}

%patch

这个宏将头部定义的补丁应用于源代码。如果定义了多个补丁,它可以用一个数字的参数来指示应用哪个补丁文件。它也接受 -b extension 参数,指示 RPM 在打补丁之前,将文件备份为扩展名是 extension 的文件。

%build

定义编译软件包所要执行的命令, 这一节一般由多个make命令组成。

%install

定义在安装软件包时将执行命令,类似于make install命令。有些spec文件还有%post-install段,用于定义在软件安装完成后的所需执行的配置工作。

%check

Command or series of commands to test the software. This normally includes things such as unit tests.

%files

定义软件包所包含的文件,分为三类:说明文档(doc),配置文件(config)及执行程序,还可定义文件存取权限,拥有者及组别。

这里会在虚拟根目录下进行,千万不要写绝对路径,而应用宏或变量表示相对路径。 如果描述为目录,表示目录中除%exclude外的所有文件。%defattr (-,root,root) 指定包装文件的属性,分别是(mode,owner,group),-表示默认值,对文本文件是0644,可执行文件是0755

%changelog

每次软件的更新内容可以记录在此到这里,保存到发布的软件包中,以便查询之用。

每条内容指令都表示一个阶段,决定着安装和卸载过程的具体操作。

在指令内容的编辑过程中,可能会遇到很多固有的属性,叫做macro,所有的属性都在文件 /usr/lib/rpm/macros中定义。常见的macro如下表所示:

macro

definition

comment

%{_sysconfdir}

/etc

%{_prefix}

/usr

can be defined to /app for flatpak builds

%{_exec_prefix}

%{_prefix}

default: /usr

%{_includedir}

%{_prefix}/include

default: /usr/include

%{_bindir}

%{_exec_prefix}/bin

default: /usr/bin

%{_libdir}

%{_exec_prefix}/%{_lib}

default: /usr/%{_lib}

%{_libexecdir}

%{_exec_prefix}/libexec

default: /usr/libexec

%{_sbindir}

%{_exec_prefix}/sbin

default: /usr/sbin

%{_datadir}

%{_datarootdir}

default: /usr/share

%{_infodir}

%{_datarootdir}/info

default: /usr/share/info

%{_mandir}

%{_datarootdir}/man

default: /usr/share/man

%{_docdir}

%{_datadir}/doc

default: /usr/share/doc

%{_rundir}

/run

%{_localstatedir}

/var

%{_sharedstatedir}

/var/lib

%{_lib}

lib64

lib on 32bit platforms

可以通过命令rpm命令查看macros的具体值。例如

rpm --eval "some text printed on %{_arch}”

rpm --eval %{_lib}

1.5.RPM编译

rpm编译的代码分为两类:本地编译代码和解释语言代码。

1.5.1.本地编译代码

Natively compiled本地编译是把编程语言编译成机器代码,生成二进制可执行文件。这种软件可以独立运行。

以这种方式构建的 RPM 包是适用于特定体系结构的。这意味着您在使用 64 位(x86_64)AMD 或 Intel 处理器的计算机上编译此类软件,则无法在 32 位(x86)AMD 或 Intel 处理器上执行。生成的包将在其名称中指定体系结构。

1.5.2.解释语言代码

某些编程语言(如 bash 或 python)无法编译为机器代码。相反,它们程序的源代码是由语言解释器或语言虚拟机逐步执行的,无需事先转换。

完全用解释型语言编写的软件不是特定于体系结构的。因此,生成的 RPM 包名称中将包含字符串 noarch。

解释型语言是可以 byte-compiled 或者 raw-interpreted (字节编译或者原始解释)。这两种类型在程序构建过程和包装过程中有所不同。

(1)Raw-interpreted programs:原始解释语言完全不需要编译,它们由解释器直接执行。

(2)Byte-compiled programs:字节编译语言需要编译成字节代码,然后由语言虚拟机执行。

2.SPEC文件案例

下面是一个入门案例。

Name:       hello-world
Version:    1
Release:    1
Summary:    Most simple RPM package
License:    FIXME

%description
This is my first RPM package, which does nothing.

%prep
# we have no source, so nothing here

%build
cat > hello-world.sh <<EOF
#!/usr/bin/bash
echo Hello world
EOF

%install
mkdir -p %{buildroot}/usr/bin/
install -m 755 hello-world.sh %{buildroot}/usr/bin/hello-world.sh

%files
/usr/bin/hello-world.sh

%changelog
# let's skip this for now

创建好文件后,可通过“rpmbuild -ba hello-world.spec”命令进行打包。

rpm打包成功后,通过“rpm -ivh hello-world-1-1.x86_64.rpm”命令进行软件安装。

3.RPM操作

RPM命令使用场景

3.1.rpm打包流程

打包流程有以下六个步骤:

(1)安装 rpmbuild

(2)构建rpm的编译目录结构: rpmbuild/ ├ BUILD ├ RPMS ├ SOURCES ├ SPECS ├ SRPMS

(3)将源码放到到 rpmbuild/SOURCES  

(4)在rpmbuild/SPECS目录创建spec文件  

(5)在rpmbuild/SPECS目录下执行打包编译: rpmbuild -bb xxxxx.spec 

(6)最终生成的rpm包

3.2.rpm命令行操作

查看rpm包中有什么:rpm2cpio kafka_.rpm | cpio -t | grep connect-runtime

提取rpm包中的文件: rpm2cpio kafka.rpm | cpio -id ./usr/local/kafka/libs/connect-runtime-1.0.0.jar

3.3.查看lib.so文件属于哪个rpm包

命令为:rpm -qf {lib.so path}