打包目录
rpm 打包目录有一些严格的层次上的要求。
rpm 的版本 <=4.4.x,rpmbuid 工具其默认的工作路径是 /usr/src/redhat。因为权限的问题,普通用户不能制作 rpm 包,制作 rpm 软件包时必须切换到 root 身份才可以。
rpm 从 4.5.x 版本开始,将 rpmbuid 的默认工作路径移动到用户家目录下的 rpmbuild目录里,即 $HOME/rpmbuild ,并且推荐用户在制作 rpm 软件包时尽量不要以 root 身份进行操作。
如果想发布 rpm 格式的源码包或者是二进制包,就要使用 rpmbuild 工具( rpm 最新打包工具)。如果我们已经根据本地源码包的成功编译安装而写了 spec 文件(该文件要以 .spec 结束),那我们就可以建立一个打包环境,也就是目录树的建立,一般是在 ~/rpmbuild 目录下建立 5 个目录。它门分别是:
BUILD
:目录用来存放打包过程中的源文件,就是来源于SOURCE
SOURCE
:用来存放打包是要用到的源文件和 patch,主要是一些tar
包SPEC
:用来存放 spec 文件SRPM
:存放打包生成的 rpm 格式的源文件RPM
:二进制文件
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 包通常用于审核和升级软件包。 |
安装工具
RPM打包使用的是 rpmbuild 命令,来自 rpm-build 包:
yum install -y rpm-build
也可以安装 rpmdevtools,这个工具部包含一些其他工具,依赖 rpm-build,所以直接安装会将 rpm-build 装上:
yum install -y rpmdevtools
Python 的编译打包工具是 setuptools。
工具使用
rpmbuild 命令使用一套标准化的「工作空间」 ,生成 %_topdir 工作目录 ~/rpmbuild,以及配置文件 ~/.rpmmacros:
rpmdev-setuptree
rpmdev-setuptree这个命令就是安装 rpmdevtools 带来的。可以看到运行了这个命令之后,在 $HOME 家目录下多了一个叫做 rpmbuild 的文件夹,里边内容如下:
$ tree rpmbuild
rpmbuild
├── BUILD
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS
rpmdev-setuptree 命令在当前用户 home/rpmbuild 目录里自动建立上述目录。
如果没有安装 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/RPMS | %_rpmdir | 标准 RPM 包目录 | 生成/保存二进制 RPM 包 |
~/rpmbuild/SRPMS | %_srcrpmdir | 源代码 RPM 包目录 | 生成/保存源码 RPM 包(SRPM) |
~/rpmbuild/BUILDROOT | %_buildrootdir | 最终安装目录 | 保存 %install 阶段安装的文件 |
rpmbuild 默认工作路径的确定,通常由在 /usr/lib/rpm/macros 这个文件里的一个叫做 %_topdir 的宏变量来定义。如果用户想更改这个目录名,rpm 官方并不推荐直接更改这个目录,而是在用户家目录下建立一个名为 .rpmmacros 的隐藏文件(Linux下隐藏文件,前面的点不能少),然后在里面重新定义 %_topdir,指向一个新的目录名。这样就可以满足某些用户的差异化需求了。.rpmmacros 文件里内容,比如:
%_topdir %(echo $HOME)/rpmbuild
%_smp_mflags %( \
[ -z "$RPM_BUILD_NCPUS" ] \\\
&& RPM_BUILD_NCPUS="`/usr/bin/nproc 2>/dev/null || \\\
/usr/bin/getconf _NPROCESSORS_ONLN`"; \\\
if [ "$RPM_BUILD_NCPUS" -gt 16 ]; then \\\
echo "-j16"; \\\
elif [ "$RPM_BUILD_NCPUS" -gt 3 ]; then \\\
echo "-j$RPM_BUILD_NCPUS"; \\\
else \\\
echo "-j3"; \\\
fi )
%__arch_install_post \
[ "%{buildarch}" = "noarch" ] || QA_CHECK_RPATHS=1 ; \
case "${QA_CHECK_RPATHS:-}" in [1yY]*) /usr/lib/rpm/check-rpaths ;; esac \
/usr/lib/rpm/check-buildroot
生成 SPEC 文件#
最重要的 SPEC 文件,命名格式一般是“软件名-版本.spec”的形式,将其拷贝到 SPECS 目录下。
如果系统有 rpmdevtools 工具,可以用
rpmdev-newspec -o name.spec
命令来生成 SPEC 文件的模板,然后进行修改:
Name: myapp
Version:
Release: 1%{?dist}
Summary:
License:
URL:
Source0:
BuildRequires:
Requires:
%description
%prep
%setup -q
%build
%configure
make %{?_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
%make_install
%files
%doc
如果没有安装 rpmdevtools,也可以自己手动创建一个 spec 文件。
SPEC 文件综述
需要遵守这些规定:软件包命名规定,打包规定 和 软件包审核规定。
"#
" 字符表示注释,但需要避免注释宏(以 %
开头),因为它们会首先被替换展开。使用 %%
注释宏。另外,还要避免在脚本命令的相同行中使用行内注释。
以下介绍了主要的标签。注意 %{name}
,%{version}
和 %{release}
代表 Name, Version 和 Release 这三个标签。只要更改标签,宏就会使用新值。
- Name: 软件包名,应与 SPEC 文件名一致。命名必须符合 软件包命名规定。
- Version: 上游版本号。请查看 版本标签规定。如果包含非数字字符,您可能需要将它们包含在 Release 标签中。如果上游采用日期作为版本号,请考虑以:
yy.mm[dd]
(例如2008-05-01
可变为8.05
) 格式作为版本号。 - Release: 发行编号。初始值为
1%{?dist}
。每次制作新包时,请递增该数字。当上游发布新版本时,请修改 Version 标签并重置 Release 的数字为1
。具体参考打包规定中的 Release 标签部分,以及 Dist tag。 - Summary: 一行简短的软件包介绍。请使用美式英语。请勿在结尾添加标点!
- Group: 指定软件包组,例如 "Applications/Engineering";执行 "
less /usr/share/doc/rpm-*/GROUPS
" 查看完整的组列表。任何包含文档的子软件包,使用 "Documentation" 组(如kernel-doc
)。 - License: 授权协议,必须是开源许可证。请不要使用旧的 Copyright 标签。协议采用标准缩写(如 "
GPLv2+
")并且描述明确(如, "GPLv2+
" 表示 GPL 2 及后续版本,而不是 "GPL
" 或 "GPLv2
" 这种不准确的写法)。参考 Licensing 和 Licensing Guidelines。如果一个软件采用多个协议,可以使用 "and
" 和 "or
"(例如 "GPLv2 and BSD
")来描述。 - URL: 该软件包的项目主页。注意:源码包 URL 请使用 Source0 指定。
- Source0: 软件源码包的 URL 地址。"
Source
" 与 "Source0
" 相同。强烈建议提供完整 URL 地址,文件名用于查找SOURCES
目录。如果可能,建议使用%{name}
和%{version}
替换 URL 中的名称/版本,这样更新时就会自动对应。下载源码包时,需要 保留时间戳。如果有多个源码包,请用Source1
,Source2
等依次列出。如果你需要添加额外文件,请将它们列在后面。更多特殊案例(如 revision control),请参考 Source URL。 - Patch0: 用于源码的补丁名称。如果你需要在源码包解压后对一些代码做修改,你应该修改代码并使用 diff 命令生成 patch 文件,然后放在
~/rpmbuild/SOURCES
目录下。一个 Patch 应该只做一种修改,所以可能会包含多个 patch 文件。 - BuildArch: 如果你要打包的文件不依赖任何架构(例如 shell 脚本,数据文件),请使用 "
BuildArch: noarch
"。RPM 架构会变成 "noarch
"。 - BuildRoot: 在 %install 阶段(%build 阶段后)文件需要安装至此位置。Fedora 不需要此标签,只有 EPEL5 还需要它。默认情况下,根目录为 "
%{_topdir}/BUILDROOT/
"。 - BuildRequires: 编译软件包所需的依赖包列表,以逗号分隔。此标签可以多次指定。编译依赖 不会 自动判断,所以需要列出编译所需的所有依赖包。常见的软件包可省略,例如
gcc
。如果有必要,你可以指定需要的最低版本(例:"ocaml >= 3.08
")。如果你需要找到包含/EGGS
文件的软件包,可执行 "rpm -qf /EGGS
"。如果你需要找到包含EGGS
程序的软件包,可执行 "rpm -qf which EGGS
"。请保持最小依赖(例如,如果你不需要 perl 的功能,可使用sed
代替),但请注意,如果不包含相关依赖,某些程序会禁用一些功能;此时,你需要添加这些依赖。auto-buildrequires
软件包可能会有帮助。 - Requires: 安装软件包时所需的依赖包列表,以逗号分隔。请注意, BuildRequires 标签是编译所需的依赖,而 Requires 标签是安装/运行程序所需的依赖。大多数情况下,
rpmbuild
会自动探测依赖,所以可能不需要 Requires 标签。然而,你也可以明确标明需要哪些软件包,或由于未自动探测所需依赖而需要手动标明。 - %description: 程序的详细/多行描述,请使用美式英语。每行必须小于等于 80 个字符。空行表示开始新段落。使用图形安装软件时会重新格式化段落;以空格开头的行被视为已格式化的格式,一般使用等宽字体显示。参考 RPM Guide。
- %prep: 打包准备阶段执行一些命令(如,解压源码包,打补丁等),以便开始编译。一般仅包含 "
%autosetup
";如果源码包需要解压并切换至NAME
目录,则输入 "%autosetup -n NAME
"。查看 %prep 部分了解更多信息。 - %build: 包含构建阶段执行的命令,构建完成后便开始后续安装。程序应该包含有如何编译的介绍。查看 %build 部分了解更多信息。
- %install: 包含安装阶段执行的命令。命令将文件从
%{_builddir}
目录安装至%{buildroot}
目录。查看 %install 部分了解更多信息。 - %check: 包含测试阶段执行的命令。此阶段在 %install 之后执行,通常包含 "
make test
" 或 "make check
" 命令。此阶段要与 %build 分开,以便在需要时忽略测试。 - %clean: 清理安装目录的命令。此阶段在 Fedora 中是多余的,仅针对 EPEL。一般只包含:rm -rf %{buildroot}
- %files: 需要被打包/安装的文件列表。查看 %files 部分了解更多信息。
- %changelog: RPM 包变更日志。请使用示例中的格式。注意,不是软件本身的变更日志。
- ExcludeArch: 排除某些架构。如果该软件不能在某些架构上正常编译或工作,通过该标签列出。
- ExclusiveArch: 列出该软件包独占的架构。
- 你可以加入一些代码片段,以便在真实系统上安装/删除包时执行这些代码(相反,%install 脚本仅将文件虚拟【pseudo】安装至 build root 目录)。这些代码称为 "scriptlets",通常用于从软件包更新系统信息。查看 "Scriptlets" 部分了解更多信息。
打包命令
在 rpmbuild/SPECS 目录下执行打包编译,切换到该目录下执行打包编译命令。
rpmbuild 命令选项#
rpmbuild 命令的选项 rpmbuild 命令有不少选项,用得比较多的有:
-bp 只解压源码及应用补丁
-bc 只进行编译
-bi 只进行安装到%{buildroot}
-bb 只生成二进制 rpm 包
-bs 只生成源码 rpm 包
-ba 生成二进制 rpm 包和源码 rpm 包
--target 指定生成 rpm 包的平台,默认会生成 i686 和 x86_64 的 rpm 包,但一般我只需要 x86_64 的 rpm 包
只生成二进制格式的 rpm 包
rpmbuild -bb 软件名-版本.spec
用此命令生成软件包,生成的文件会在刚才建立的RPM目录下存在。
只生成 src 格式的 rpm 包
rpmbuild -bs 软件名-版本.spec
生成的文件会在刚才建立的SRPM目录下存在。
只需要生成完整的源文件
rpmbuild -bp 软件名-版本.spec
源文件存在目录 BUILD 下。可能对这个命令不太明白,这个命令的作用就是把 tar 包解开然后把所有的补丁文件合并而生成一个完整的具最新功能的源文件。
完全打包
rpmbuild -ba 软件名-版本.spec
软件包制作完成后可用 rpm 命令查询