目录
2.1.1.2. 用 Python 编写的 Hello World
3.2.2 使用 rpmdev-newspec 创建新的 SPEC 文件
第 1 章、RPM 打包入门
以下部分介绍 RPM 打包的概念及其主要优点。
1.1 RPM打包简介
RPM 包管理器 (RPM) 是在 RHEL、CentOS 和 Fedora 上运行的包管理系统。您可以使用 RPM 来分发、管理和更新为上述任何操作系统创建的软件。
1.2 RPM优势
与在传统存档文件中分发软件相比,RPM 包管理系统具有几个优势。
RPM 使您能够:
- 使用标准包管理工具(如 Yum 或 PackageKit)安装、重新安装、删除、升级和验证包。
- 使用已安装包的数据库来查询和验证包。
- 使用元数据来描述包、其安装说明和其他包参数。
- 将软件源、补丁和完整的构建说明打包到源码包和二进制包中。
- 将包添加到
Yum
存储库。 - 使用 GNU 隐私卫士 (GPG) 签名密钥对包进行数字签名。
1.3 创建你的第一个RPM包
创建 RPM 包可能很复杂。这是一个完整的、有效的 RPM 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
rpmdev-setuptree
命令创建多个工作目录。由于这些目录永久存储在 $HOME 中,因此无需再次使用此命令。
rpmbuild
命令创建实际的 rpm 包。此命令的输出可以类似于:
... [SNIP]
Wrote: /home/<username>/rpmbuild/SRPMS/hello-world-1-1.src.rpm
Wrote: /home/<username>/rpmbuild/RPMS/x86_64/hello-world-1-1.x86_64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.wgaJzv
+ umask 022
+ cd /home/<username>/rpmbuild/BUILD
+ /usr/bin/rm -rf /home/<username>/rpmbuild/BUILDROOT/hello-world-1-1.x86_64
+ exit 0
/home/<username>/rpmbuild/RPMS/x86_64/hello-world-1-1.x86_64.rpm
文件是您的第一个 RPM 包。它可以安装在系统中并进行测试。
第二章、准备用于RPM打包的软件
本节介绍如何为 RPM 打包准备软件。要做到这一点,不需要知道如何编码。但是,您需要了解基本概念,例如什么是源代码以及如何制作程序。
2.1 什么是源代码
本部分解释了什么是源代码,并展示了用三种不同的编程语言编写的程序的示例源代码。
源代码是人类可读的计算机指令,描述了如何执行计算。源代码使用编程语言表示。
2.1.1 源代码示例
本文档介绍了用三种不同的编程语言编写的Hello World
程序的三个版本:
每个版本的打包方式都不同。
Hello World
程序的这些版本涵盖了 RPM 打包器的三个主要用例。
2.1.1.1 用bash编写的Hello World
bello项目用bash实现Hello World。该实现只包含bello shell
脚本。该程序的目的是在命令行上输出Hello World。
bello
文件的语法如下:
#!/bin/bash
printf "Hello World\n"
2.1.1.2. 用 Python 编写的 Hello World
pello 项目是用 Python 实现Hello World
的。实现仅包含pello.py
程序。该程序的目的是在命令行上输出Hello World
。
pello.py
文件的语法如下:
#!/usr/bin/python3
print("Hello World")
2.1.1.3 用C语音编写的Hello World
cello项目用c语言实现了Hello World。该实现只包含cello.c和
Makefile文件,因此生成的tar.gz归档文件除了LICENSE文件之外还有两个文件。
该程序的目的是在命令行上输出Hello World。
cello.c
文件的语法如下:
#include <stdio.h>
int main(void) {
printf("Hello World\n");
return 0;
}
2.2. 程序是如何制作的
从人类可读的源代码转换为机器代码(计算机执行程序所遵循的指令)的方法包括:
- 该程序是本地编译的。
- 该程序通过原始解释进行解释。
- 该程序通过字节编译进行解释。
2.2.1. 原生编译代码
本机编译软件是用编程语言编写的软件,该语言编译为机器代码,并生成二进制可执行文件。此类软件可以独立运行。
以这种方式构建的 RPM 包是特定于体系结构的。
如果在使用 64 位 (x86_64) AMD 或 Intel 处理器的计算机上编译此类软件,则它不会在 32 位 (x86) AMD 或 Intel 处理器上执行。生成的包在其名称中指定了体系结构。
2.2.2 解释代码
某些编程语言(例如 bash 或 Python)不会编译为机器代码。取而代之的是,他们的程序源代码是由语言解释器或语言虚拟机逐步执行的,无需事先转换。
完全用解释型编程语言编写的软件不是特定于体系结构的。因此,生成的 RPM 包的名称中包含noarch
字符串。
解释型语言是原始解释程序或字节编译程序。这两种类型在程序构建过程和打包过程中有所不同。
2.2.2.1 原始解释程序
原始解释的语言程序不需要编译,由解释器直接执行。
2.2.2.2 字节编译程序
字节编译的语言需要被编译成字节码,然后由语言虚拟机执行。
注意
有些语言提供了一种选择:它们可以是原始解释的,也可以是字节编译的。
2.3 从源码构建软件
本部分介绍如何从源代码构建软件。
对于用编译语言编写的软件,源代码会经历一个构建过程,生成机器代码。此过程通常称为编译或翻译,因语言而异。由此产生的构建软件可以运行,这使得计算机执行程序员指定的任务。
对于用原始解释语言编写的软件,源代码不是构建的,而是直接执行的。
对于用字节编译的解释型语言编写的软件,源代码被编译成字节码,然后由语言虚拟机执行。
2.3.1 原生代码编译
本节展示如何将用 C 语言编写的cello.c
程序构建为可执行文件。
cello.c
#include <stdio.h>
int main(void) {
printf("Hello World\n");
return 0;
}
2.3.1.1 手动构建
如果你想手动构建cello.c程序,使用这个过程:
1、调用GNU编译器集合中的C编译器将源代码编译成二进制文件:
gcc -g -o cello cello.c
2、执行结果输出二进制cello
:
$ ./cello
Hello World
2.3.1.2 自动构建
大型软件通常使用自动构建,通过创建Makefile文件,然后运行GNU make实用程序来完成。
如果你想使用自动构建来构建cello.c程序,使用这个过程:
1、要设置自动构建,请在Makefile与cello.c 相同的目录中创建包含以下内容的文件。
Makefile
cello:
gcc -g -o cello cello.c
clean:
rm cello
请注意,cello和 clean下的行必须以制表符空格开头。
2、要构建软件,请运行以下make命令:
$ make
make: 'cello' is up to date.
3、由于已经有可用的构建版本,因此请运行make clean
命令,然后再次运行make
命令:
$ make clean
rm cello
$ make
gcc -g -o cello cello.c
注意
尝试在另一个构建之后构建程序不起作用。
$ make
make: 'cello' is up to date.
现在,您已经手动编译了程序,并使用构建工具编译了程序。
2.3.2 解释代码
本节介绍如何对用 Python 编写的程序进行字节编译,以及如何对用 bash 编写的程序进行原始解释。
注意在下面的两个示例中,文件顶部的#!行称为 shebang,它不是编程语言源代码的一部分。
shebang 允许使用文本文件作为可执行文件:系统程序加载器解析包含 shebang 的行以获取二进制可执行文件的路径,然后将其用作编程语言解释器。该功能要求将文本文件标记为可执行文件。
2.3.2.1 字节编译代码
本节介绍如何将用 Python 编写的pello.py
程序编译为字节码,然后由 Python 语言虚拟机执行。
Python 源代码也可以进行原始解释,但字节编译版本更快。因此,RPM 打包器更喜欢打包字节编译版本以分发给最终用户。
pello.py
#!/usr/bin/python3
print("Hello World")
字节编译程序的过程因以下因素而异:
- 程序设计语言
- 语言的虚拟机
- 与该语言一起使用的工具和流程
注意
使用此过程编译pello.py
为字节码:
1、对pello.py
文件进行字节编译:
$ python -m compileall pello.py
$ file pello.pyc
pello.pyc: python 2.7 byte-compiled
2、执行pello.pyc
中的字节码:
$ python pello.pyc
Hello World
2.3.2.2 原始代码解释
本节展示如何原始解释用 bash shell 内置语言编写的bello
程序。
bello
#!/bin/bash
printf "Hello World\n"
用 shell 脚本语言(如 bash)编写的程序是原始解释的。
将带有源代码的文件设置为可执行文件并运行它:
$ chmod +x bello
$ ./bello
Hello World
2.4 软件打补丁
本节解释了如何对软件进行修补。在RPM打包中,我们不直接修改原始源代码,而是保留它,并在其上使用补丁。补丁是一种更新其他源代码的源代码。它的格式为diff,因为它表示两个版本之间的差异。diff是使用diff工具创建的,随后使用patch工具将其应用于源代码。
注意
软件开发人员经常使用版本控制系统(如 git)来管理他们的代码库。这些工具提供了它们自己的方法来创建差异或修补软件。
以下示例演示如何使用diff
从原始源代码创建补丁,以及如何使用 patch
应用补丁。在后面的部分中创建 RPM 时,将使用修补;参见第 3.2 节 “使用 SPEC 文件”。
此过程显示如何根据cello.c
的原始源代码创建 的修补程序。
1、保留原始源代码:
$ cp -p cello.c cello.c.orig
-p
选项用于保留模式、所有权和时间戳。
2、cello.c
根据需要进行修改:
#include <stdio.h>
int main(void) {
printf("Hello World from my very first patch!\n");
return 0;
}
3、使用diff
实用程序生成补丁:
$ diff -Naur cello.c.orig cello.c
--- cello.c.orig 2016-05-26 17:21:30.478523360 -0500
+ cello.c 2016-05-27 14:53:20.668588245 -0500
@@ -1,6 +1,6 @@
#include<stdio.h>
int main(void){
- printf("Hello World!\n");
+ printf("Hello World from my very first patch!\n");
return 0;
}
\ No newline at end of file
以 - 开头的行是从原始源代码中删除的,并被以 + 开头的行替换。建议在使用diff命令时使用Naur选项,因为它适合大多数常见用例。然而,在这个特定情况下,只需要 -u 选项。特定选项确保了以下内容:
-N(或 --new-file) - 将缺失的文件视为空文件进行处理。
-a(或 --text) - 将所有文件视为文本。因此,diff将其分类为二进制文件的文件不会被忽略。
-u(或 -U NUM 或 --unified[=NUM]) - 以统一上下文的输出形式返回输出 NUM(默认值为 3)行。这是一种易于阅读的格式,在将补丁应用于更改后的源代码树时允许模糊匹配。
-r(或 --recursive) - 递归比较发现的任何子目录。
4、将补丁保存到一个文件:
$ diff -Naur cello.c.orig cello.c > cello-output-first-patch.patch
5、恢复cello.c
原始文件:
$ cp cello.c.orig cello.c
以下步骤展示了如何使用 cello-output-first-patch.patch
对 cello.c
进行修补,构建修补后的程序并运行它。
1、将patch
补丁文件重定向到以下命令:
$ patch < cello-output-first-patch.patch
patching file cello.c
2、检查cell .c的内容现在是否反映了补丁:
$ cat cello.c
#include<stdio.h>
int main(void){
printf("Hello World from my very first patch!\n");
return 1;
}
3、构建并运行打过补丁的cell .c:
$ make clean
rm cello
$ make
gcc -g -o cello cello.c
$ ./cello
Hello World from my very first patch!
2.5 安装任意工件
类Unix系统使用文件系统层次标准(FHS)来指定适合特定文件的目录。从RPM包安装的文件是根据FHS放置的。例如,执行文件应该放在系统$PATH变量中的一个目录下。
在本文档的上下文中,任意工件是指从RPM安装到系统中的任何内容。对于RPM和系统,它可以是脚本、从包的源代码编译的二进制文件、预编译的二进制文件或任何其他文件。
本节描述了在系统中放置任意工件的两种常见方式:
- 第2.5.1节,“使用install命令”
- 第2.5.2节,“使用make install命令”
2.5.1 使用install命令
打包者经常在构建自动化工具(如 GNU make)不是最佳的情况下使用install
命令;例如,如果打包的程序不需要额外的开销。
install
命令由 coreutils 提供给系统,它将工件放置在文件系统中的指定目录中,并具有一组指定的权限。
以下过程使用先前创建为任意工件的bello
文件作为此安装方法的主题。
1、运行以下install
命令,将bello
文件放入具有可执行脚本常见权限的/usr/bin
目录中:
$ sudo install -m 0755 bello /usr/bin/bello
2、在不指定完整路径的情况下从任意目录执行bello:
$ cd ~
$ bello
Hello World
2.5.2 使用make install 命令
使用make install命令可以自动地将构建好的软件安装到系统中。在这个
情况下,您需要在Makefile中指定如何将任意工件安装到系统中
通常由开发人员编写。
此过程显示了如何将构建工件安装到系统上的选定位置。
1、将install
部分添加到Makefile文件
:
Makefile
cello:
gcc -g -o cello cello.c
clean:
rm cello
install:
mkdir -p $(DESTDIR)/usr/bin
install -m 0755 cello $(DESTDIR)/usr/bin/cello
请注意cello
、clean
、和install
下的行必须以制表符空格开头。
注意
$(DESTDIR) 变量是 GNU make 内置的,通常用于指定安装到与根目录不同的目录。
现在,您不仅可以使用Makefile
构建软件,还可以将其安装到目标系统。
2、构建并安装cello.c
程序:
$ make
gcc -g -o cello cello.c
$ sudo make install
install -m 0755 cello /usr/bin/cello
因此,现在位于cello
$PATH
变量中列出的目录中。
3、从任何目录执行cello
,而不指定其完整路径:
$ cd ~
$ cello
Hello World
2.6 准备打包的源代码
开发人员通常将软件作为源代码的压缩存档分发,然后使用这些压缩文件来创建包。RPM 打包器使用现成的源代码存档。
软件应与软件许可证一起分发。此过程使用 GPLv3 许可证文本作为LICENSE
文件的示例内容。
创建一个LICENSE
文件,并确保它包含以下内容:
$ cat /tmp/LICENSE
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.
其他资源
- 可以在此处找到本节中创建的代码。
2.7 将源代码放入压缩包
本节介绍如何将第 2.1.1 节 “源代码示例” 中介绍的三个Hello World
程序分别放入 gzip 压缩的压缩包中,这是发布软件以供以后打包分发的常用方法。
2.7.1 将 bello 项目放入 tarball 中
bello项目在bash中实现了Hello World。该实现仅包含bello脚本,因此生成的tar.gz归档文件除了LICENSE文件外只会包含一个文件。该过程展示了如何为bello项目准备分发。
先决条件
考虑到这是该程序的0.1版本。
1、将所有必需的文件放入一个目录中:
$ mkdir /tmp/bello-0.1
$ mv ~/bello /tmp/bello-0.1/
$ cp /tmp/LICENSE /tmp/bello-0.1/
2、创建用于分发的存档文件,并将其移动到~/rpmbuild/SOURCES/
目录中,该目录是rpmbuild
命令存储用于构建包的文件的默认目录:
$ cd /tmp/
$ tar -cvzf bello-0.1.tar.gz bello-0.1
bello-0.1/
bello-0.1/LICENSE
bello-0.1/bello
$ mv /tmp/bello-0.1.tar.gz ~/rpmbuild/SOURCES/
有关用 bash 编写的示例源代码的更多信息,请参见第 2.1.1.1 节 “用 bash 编写的 Hello World”。
2.7.2 将 pello 项目放入 tarball 中
pello项目用Python实现了Hello World。该实现只包含pello.py
因此,生成的tar.gz归档文件除了LICENSE文件之外将只有一个文件。
这个过程展示了如何准备分发的pello项目。
先决条件
考虑到这是程序的0.1.1版本
1、将所有必需的文件放入一个目录中:
$ mkdir /tmp/pello-0.1.2
$ mv ~/pello.py /tmp/pello-0.1.2/
$ cp /tmp/LICENSE /tmp/pello-0.1.2/
2、创建用于分发的存档文件,并将其移动到/rpmbuild/SOURCES/
目录中,该目录是~rpmbuild
命令存储用于构建包的文件的默认目录:
$ cd /tmp/
$ tar -cvzf pello-0.1.2.tar.gz pello-0.1.2
pello-0.1.2/
pello-0.1.2/LICENSE
pello-0.1.2/pello.py
$ mv /tmp/pello-0.1.2.tar.gz ~/rpmbuild/SOURCES/
2.7.3 将cello项目放入tarball
cello项目是用 C 语言实现Hello World
的。该实现仅包含 cello.c
和 Makefile
文件,因此生成的tar.gz
存档将有两个文件与LICENSE
文件分开。
注意该文件不会与程序一起在存档中分发。RPM Packager 在构建 RPM 时应用补丁。patch
补丁将与.tar.gz存档一起放入/rpmbuild/SOURCES/目录中。
此过程说明如何准备要分发的cello项目。
先决条件
考虑到这是程序的1.0
版本。
1、将所有必需的文件放入一个目录中:
$ mkdir /tmp/cello-1.0
$ mv ~/cello.c /tmp/cello-1.0/
$ mv ~/Makefile /tmp/cello-1.0/
$ cp /tmp/LICENSE /tmp/cello-1.0/
2、创建用于分发的存档文件,并将其移动到rpmbuild/SOURCES/
目录中,该目录是rpmbuild
命令存储用于构建包的文件的默认目录:
$ cd /tmp/
$ tar -cvzf cello-1.0.tar.gz cello-1.0
cello-1.0/
cello-1.0/Makefile
cello-1.0/cello.c
cello-1.0/LICENSE
$ mv /tmp/cello-1.0.tar.gz ~/rpmbuild/SOURCES/
3、添加补丁:
$ mv ~/cello-output-first-patch.patch ~/rpmbuild/SOURCES/
第三章、打包软件
3.1 RPM包
本节介绍 RPM 打包格式的基础知识。
3.1.1 什么是RPM
RPM 包是一个包含其他文件及其元数据(有关系统所需文件的信息)的文件。
具体来说,RPM 包由cpio
归档文件组成。
cpio
档案包含:
- 文件
-
RPM 标头(包元数据)
rpm
包管理器使用此元数据来确定依赖项、文件安装位置以及其他信息。
RPM 包的类型
RPM 包有两种类型。这两种类型共享文件格式和工具,但具有不同的内容和不同的用途:
-
源 RPM (SRPM)
SRPM包含源代码和SPEC文件,其中描述了如何将源代码构建为二进制RPM。或者,还包括源代码的补丁。
-
二进制 RPM
二进制 RPM 包含从源代码和补丁构建的二进制文件。
3.1.2 列出 RPM 打包工具的实用程序
以下过程演示如何列出包提供的rpmdevtools
实用程序。
先决条件
为了能够使用 RPM 打包工具,您需要安装rpmdevtools
包,该包提供了几个用于打包 RPM 的实用程序。
# yum install rpmdevtools
列出 RPM 打包工具的实用程序:
$ rpm -ql rpmdevtools | grep bin
其他信息:
- 有关上述实用程序的更多信息,请参阅其手册页或帮助对话框。
3.1.3. 设置 RPM 打包工作区
本节介绍如何使用rpmdev-setuptree
实用程序设置目录布局,即 RPM 打包工作区。
先决条件
rpmdevtools
软件包必须安装在您的系统上:
# yum install rpmdevtools
- 运行
rpmdev-setuptree
实用程序:
$ rpmdev-setuptree
$ tree ~/rpmbuild/
/home/<username>/rpmbuild/
|-- BUILD
|-- RPMS
|-- SOURCES
|-- SPECS
`-- SRPMS
5 directories, 0 files
创建的目录用于以下目的:
目录 | 目的 |
BUILD | 构建包时,将在 |
RPMS | 二进制 RPM 在此处创建,位于不同体系结构的子目录中,例如在 |
SOURCES | 在这里,打包器放置压缩的源代码存档和补丁。 |
SPECS | 打包器将 SPEC 文件放在这里。 |
SRPMS | 当 |
3.1.4. 什么是SPEC文件
您可以将SPEC文件理解为rpmbuild工具用来构建RPM的配方。SPEC文件通过在多个部分中定义指令,为构建系统提供必要的信息。这些部分在前言和主体部分中定义。前言部分包含一系列在主体部分中使用的元数据项。主体部分则代表指令的主要部分。
3.1.4.1. 序言项目
下表列出了 RPM SPEC 文件的 Preamble 部分中经常使用的一些指令。
SPEC指令 | 定义 |
---|---|
| 包的基本名称,应与 SPEC 文件名匹配。 |
| 软件的上游版本号。 |
| 此版本软件的发布次数。通常,将初始值设置为 1%{?dist},并随着包的每个新版本而递增。当构建新的软件 |
| 一行简短的包摘要。 |
| 正在打包的软件的许可证。 |
| 有关该程序的详细信息的完整 URL。大多数情况下,这是正在打包的软件的上游项目网站。 |
| 上游源代码的压缩存档的路径或 URL(未修补,补丁在其他地方处理)。这应该指向存档的可访问且可靠的存储,例如,上游页面,而不是打包者的本地存储。如果需要,可以添加更多 SourceX 指令,每次增加数量,例如:Source1、Source2、Source3 等。 |
| 如有必要,要应用于源代码的第一个修补程序的名称。 该指令可以通过两种方式应用:在 Patch 末尾带或不带数字。 如果未给出编号,则在内部为条目分配一个编号。也可以使用 Patch0、Patch1、Patch2、Patch3 等显式给出数字。 可以使用 %patch0、%patch1、%patch2 巨集等逐个应用这些补丁。宏在 RPM SPEC 文件的 Body 部分的 %prep 指令中应用。或者,您可以使用 %autopatch 巨集,该 %autopatch 会自动按照 SPEC 文件中给出的顺序应用所有补丁。 |
| 如果包不依赖于体系结构,例如,如果完全用解释型编程语言编写,请将此项设置为 |
| 用逗号或空格分隔的包列表,用于构建用编译语言编写的程序。在 SPEC 文件中,可以有多个 |
| 以逗号或空格分隔的软件包列表,软件在安装后需要运行。在 SPEC 文件中,可以有多个条目 ,每个 |
| 如果某个软件无法在特定的处理器架构上运行,则可以在此处排除该架构。 |
|
|
| 这个指令改变了更新的工作方式,取决于是否rpm命令直接在命令行中使用或执行升级 通过更新或依赖项解决程序。在命令行上使用时,RPM移除所有与已安装的过时包匹配的包。 当使用更新或依赖项解析器时,包含matching Obsoletes:作为更新添加并替换匹配包。 |
| 如果 |
Name
、 Version
和Release
指令构成 RPM 包的文件名。RPM 包维护者和系统管理员通常将这三个指令称为 N-V-R 或 NVR,因为 RPM 包文件名具有NAME-VERSION-RELEASE
格式。
以下示例演示如何通过查询rpm
命令来获取特定包的 NVR 信息。
例 3.1.查询 rpm 以提供 bash 包的 NVR 信息
$ rpm -q bash
bash-4.2.46-34.el7.x86_64
这里,bash 是包名,4.2.46 是版本,34.el7 是发布号。最后的标记是 x86_64,它表示架构。与NVR不同,架构标记不在RPM打包者的直接控制之下,而是由rpmbuild构建环境定义。唯一的例外是架构无关的noarch包。
主体项目
下面的表格列出了RPM SPEC文件的主体部分中使用的项目。
表3.2. RPM SPEC文件主体部分中使用的项目
3.1.4.3. 高级项目
SPEC 文件还可以包含高级项,例如 Scriptlet 或触发器。它们在最终用户系统上的安装过程中的不同时间点生效,而不是在构建过程中生效。
3.1.5. 构建根
在 RPM 打包的上下文中,buildroot 是一个 chroot 环境。这意味着构建产物被放置在这里,使用与最终用户系统中未来层次结构相同的文件系统层次结构,buildroot 充当根目录。构建产物的放置应符合最终用户系统的文件系统层次结构标准。
buildroot 中的文件随后被放入一个 cpio 存档中,该存档成为 RPM 的主要部分。当 RPM 安装在最终用户的系统上时,这些文件会被提取到根目录中,保持正确的层次结构。
从版本 6 开始,rpmbuild 程序有其自己的默认值。覆盖这些默认值会导致几个问题;因此,{RH} 不建议定义您自己的宏值。您可以使用来自 rpmbuild 目录的默认值的 %{buildroot} 宏。
3.1.6 RPM宏
RPM 宏是一种简单的文本替换,可以根据在使用某些内置功能时对语句的可选评估进行条件分配。因此,RPM 可以为您执行文本替换。
一个示例用法是在 SPEC 文件中多次引用打包软件的版本。您只需在 %{version} 宏中定义版本一次,并在整个 SPEC 文件中使用该宏。每次出现都会自动替换为您之前定义的版本。
注意
如果看到一个不熟悉巨集,可以使用以下命令对其进行评估:
$ rpm --eval %{_bindir}
/usr/bin
计算 %{_bindir} 和 %{_libexecdir} 宏
$ rpm --eval %{_bindir}
/usr/bin
$ rpm --eval %{_libexecdir}
/usr/libexec
其中一个常用的宏是%{?函数使用的是哪个发行版
构建(发布标签)。
# On a RHEL 8.x machine
$ rpm --eval %{?dist}
.el8
3.2 处理 SPEC 文件
下表还对每个程序进行了全面描述。
软件名称 | 示例说明 |
bello | 用原始解释型编程语言编写的程序。它演示了何时不需要构建源代码,而只需要安装源代码。如果需要打包预编译的二进制文件,也可以使用此方法,因为二进制文件也只是一个文件。 |
pello | 用字节编译的解释型编程语言编写的程序。它演示了对源代码进行字节编译和安装字节码 - 生成的预优化文件。 |
cello | 用本机编译的编程语言编写的程序。它演示了将源代码编译为机器代码并安装生成的可执行文件的常见过程。 |
Hello World!
的实现包括:
作为先决条件,需要将这些实现放入目录中。~/rpmbuild/SOURCES
3.2.1 创建新的SPEC文件的方法
要打包新软件,您需要创建一个新的 SPEC 文件。
有两种方法可以实现此目的:
- 从头开始手动编写新的 SPEC 文件
-
使用实用程序
rpmdev-newspec
此实用程序将创建一个未填充的 SPEC 文件,然后您填写必要的指令和字段。
注意一些以程序员为中心的文本编辑器使用自己的 SPEC 模板预填充新.spec文件。
rpmdev-newspec
实用程序提供了一种与编辑器无关的方法。
3.2.2 使用 rpmdev-newspec 创建新的 SPEC 文件
以下过程演示如何使用rpmdev-newspec
实用程序为上述三个程序中的每一个以下过程演示如何使用该实用程序为上述三个程序中的每一个Hello World!
程序创建 SPEC 文件。程序创建 SPEC 文件。
切换到~/rpmbuild/SPECS
目录并使用rpmdev-newspec
实用程序:
$ cd ~/rpmbuild/SPECS
$ rpmdev-newspec bello
bello.spec created; type minimal, rpm version >= 4.11.
$ rpmdev-newspec cello
cello.spec created; type minimal, rpm version >= 4.11.
$ rpmdev-newspec pello
pello.spec created; type minimal, rpm version >= 4.11.
~/rpmbuild/SPECS/
目录现在包含三个名为bello.spec
、cello.spec
和 pello.spec
的 SPEC 文件。
注意rpmdev-newspec 工具不使用任何特定于某个特定 Linux 发行版的指南或约定。然而,本文件的目标是,因此在引用 RPM 的 Buildroot 时,%{buildroot} 表示法比 $RPM_BUILD_ROOT 表示法更受欢迎,以便与 SPEC 文件中定义或提供的所有其他宏保持一致。
3.2.3. 修改原始 SPEC 文件以创建 RPM
以下程序展示了如何修改 rpmdev-newspec 提供的输出 SPEC 文件以创建 RPM。
先决条件
确保:
- 特定程序的源代码已放置在 ~/rpmbuild/SOURCES/ 目录中。
- 未填充的 SPEC 文件 ~/rpmbuild/SPECS/<name>.spec 文件已由 rpmdev-newspec 工具创建。
程序步骤
-
打开 rpmdev-newspec 工具提供的 ~/rpmbuild/SPECS/<name>.spec 文件输出模板。
-
填充 SPEC 文件的第一部分: 第一部分包括这些指令,这些指令由 rpmdev-newspec 组合在一起:
- Name
- Version
- Release
- Summary
-
Name 已作为参数指定给 rpmdev-newspec。
将 Version 设置为与源代码的上游发布版本匹配。Release 自动设置为 1%{?dist},初始值为 1。在未更改上游发布 Version 的情况下(例如当包括补丁时),每次更新包时递增初始值。当出现新的上游发布时,将 Release 重置为 1。Summary 是对该软件的简短说明,一般为一行。
-
填充 License、URL 和 Source0 指令: License 字段是与上游发布的源代码相关的许可协议。如何在 SPEC 文件中标记 License 的确切格式将取决于您所遵循的特定 RPM 基 Linux 发行版指南。例如,您可以使用 GPLv3+。
URL 字段提供上游软件网站的 URL。为确保一致性,使用 RPM 宏变量 %{name},并使用 https://example.com/%{name}。
Source0 字段提供上游软件源代码的 URL。它应直接链接到要打包的特定版本软件。需要注意的是,本文档中给出的示例 URL 包含硬编码的值,未来可能会发生变化。同样,发布版本也可能会改变。为简化这些可能的未来变化,请使用 %{name} 和 %{version} 宏。使用这些宏后,只需在 SPEC 文件中更新一个字段。
-
填充 BuildRequires、Requires 和 BuildArch 指令: BuildRequires 指定包的构建时依赖关系。 Requires 指定包的运行时依赖关系。 这是用解释型编程语言编写的软件,没有原生编译的扩展。因此,添加 BuildArch 指令并设置为 noarch 值。这告诉 RPM 此包不需要绑定到构建它的处理器架构。
-
填充 %description、%prep、%build、%install、%files 和 %license 指令: 这些指令可以看作是章节标题,因为它们可以定义多行、多指令或脚本任务的执行。
%description 是对软件比 Summary 更长、更详细的描述,包含一个或多个段落。
%prep 部分指定如何准备构建环境。通常涉及解压源代码的压缩归档、应用补丁以及解析源代码中提供的信息以供 SPEC 文件后续部分使用。在这一部分中,您可以使用内置的 %setup -q 宏。
%build 部分指定如何构建软件。
%install 部分包含 rpmbuild 如何将软件安装到 BUILDROOT 目录中的指令。这个目录是一个空的 chroot 基目录,类似于最终用户的根目录。这里可以创建任何将包含安装文件的目录。要创建这样的目录,您可以使用 RPM 宏,而不必硬编码路径。
%files 部分指定该 RPM 提供的文件列表及其在最终用户系统上的完整路径。
在这一部分中,您可以使用内置宏来指示各种文件的角色。这对于使用命令 []rpm 命令查询包文件清单元数据非常有用。例如,若要指示 LICENSE 文件是软件许可证文件,请使用 %license 宏。
-
最后一部分 %changelog 是每个版本-发布的日期戳条目的列表。它们记录打包变化,而非软件变化。打包变化的示例:添加补丁、更改 %build 部分的构建过程。
遵循以下格式作为第一行: 以 * 字符开头,后跟 星期几 月 日 年 姓 名 <邮箱> - 版本-发布。
遵循以下格式作为实际更改条目: 每个更改条目可以包含多个项目,每个项目对应一项更改。 每个项目从新行开始。 每个项目以 - 字符开头。
您现在已经为所需程序编写了完整的 SPEC 文件。 有关用不同编程语言编写的 SPEC 文件的示例,请参见: