我常用的系统是CentOS,所以本文针对平常使用的软件,但是没有提供RPM包的,自己制作RPM包。

首先介绍一下制作RPM包所需要用到的工具,目前我使用较多的CentOS7,所以以下以此平台为例。

安装需要的工具

yum install rpm-build rpm-devel rpmdevtools

了解RPM打包过程

rpm-build包中包含一个rpmbuild命令,此命令读取一个name-version.spec描述文件,根据描述文件中规定的一系列步骤,执行打包操作。

这些步骤都是规定好的,有些是必须的,有些是可省略的。这些步骤在之后编写.spec文件时再细说。

生成打包目录结构

默认使用系统的一些目录,不便于管理。
一般自行创建一个目录结构,可以使用rpmdev-setuptree命令生成目录树。

rpmdev-setuptree

此命令会在用户家目录中生成一个名为rpmbuild的顶级目录,其中包含的目录如下。

tree ~/rpmbuild
.
├── BUILD
├── BUILDROOT
├── RPMS
├── SOURCES
├── SPECS
└── SRPMS

说明一下这些目录的用途:

  • BUILD:存放编译生成的临时文件
  • BUILDROOT:最终生成的RPM临时安装目录
  • RPMS:最终的RPM包
  • SOURCES:存放软件源码
  • SPECS:存在spec描述文件
  • SRPMS:存在生成的RPM对应的源码包

此外rpmdev-setuptree还在家目录生成一个隐藏文件`,这个文件更改了rpmbuild用到的一些宏。例如将顶级目录设置成~/rpmbuild`,否则rpmbuild使用的将是系统默认路径。

cat ~/.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描述文件时直接使用,对应如下。

  • BUILD:%_buiddir
  • BUILDROOT:%_buildrootdir
  • RPMS:%_rpmdir
  • SOURCES:%_sourcedir
  • SPECS:%_specdir
  • SRPMS:%_srcrpmdir

打包执行的过程

  1. 将需要打包的软件源码和补丁包放到%sourcedir目录中,源码需要是tar.gz格式。
  2. rpmbuild会将源码拷贝到%builddir中,如果有补丁,也会应用补丁到此目录。
  3. 编译源码生成二进制文件。
  4. 进行软件的安装,实际上就是将最终生成的二进制文件复制到%buildrootdir,相对应目录结构就是最终软件安装的目录。例如希望安装到/usr/bin/hello,对应的就是~/rpmbuild/BUILDROOT/usr/bin/hello。
  5. 执行检查,运行软件的测试,一些临时目录的清理工作也可以放在此处。
  6. 生成二进制文件rpm包,并放到%rpmdir目录下,按照系统架构进行分类。例如典型的x86平台,生成的rpm包位置为~/rpmbuild/RPMS/x86_64/hello-1.0.0.rpm。
  7. 生成rpm包对应的源码包,放到%srcrpmdir,但是源码不区分平台,例如上面的二进制包对应的源码包为~/rpmbuild/SRPMS/hello-1.0.0.src.rpm。

SPEC文件编写

上述所有的打包步骤都是在spec文件中描述的,所以这个文件至关重要。spec文件有特定的结构,使用rpmdev-newspec命令生成一个模板文件,最好是用软件名称和版本命令,便于日后维护。

cd ~/rpmbuild/SPECS
rpmdev-newspec hello-1.0.0
cat hello-1.0.0.spec

Name:           hello-1.0.0
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



%changelog

我们一步一步来分析这个描述文件。首先是头信息,描述了软件名称,版本号等一些关键信息。以及这个软件编译时需要依赖的包和安装时依赖的包。

Name:           hello-1.0.0
Version:
Release:        1%{?dist}
Summary:

License:
URL:
Source0:

BuildRequires:
Requires:

然后是软件的详细描述。

%description

编译前的准备工作,默认操作使用了一个宏%setup,目的是把源码从%sourcedir复制并且解压到%builddir中,所以会有要求源码是tar.gz格式,如果是其他格式,这里就要自己写了,不能用宏命令。-q是静默的意思。

%prep
%setup -q

执行源码的编译工作。%configure宏设置一些编译参数,例如设置前缀为/usr。

%build
%configure
make %{?_smp_mflags}

执行软件的安装,%make_install实际上调用的是make install。

%install
rm -rf $RPM_BUILD_ROOT
%make_install

指定最终rpm中包含的二进制文件,设置文件权限等。

%files
%doc
%changelog

RPM打包示例

好了,RPM打包的一些基础已经介绍完了。这一步将用一个示例,实践一下。

准备源码包

用我们最熟悉的Hello Word为例,目标是编译一个二进制文件hello,安装到/usr/bin目录下,执行命令输出“Hello World!”。

用C编写代码并且编写对应的Makefile,方便后续编译。

make dir hello-1.0.0
touch hello.c
touch Makefile

hello.c

#include <stdio.h>

int main() {
    printf("Hello World!\n");
    return 0;
}

使用autoconf工具生成Makefile,不在此篇文章叙述范围内。

将源码目录打包,并且放到%_sourcedir目录中,安装软件名称-版本号的方式命名。

tar czvf hello-1.0.0.tar.gz hello-1.0.0
mv hello-1.0.0.tar.gz ~/rpmbuild/SOURCES

编写spec文件

rpmdev-newspec hello-1.0.0

cat hello-1.0.0.spec

Name:           hello
Version:        1.0.0
Release:        1%{?dist}
Summary:        Say Hello World!

License:        GPL
URL:            https://www.simaek.com
Source0:        hello-1.0.0.tar.gz

BuildRequires:  gcc
Requires:       gcc

%description
C program say Hello World!

%prep
%setup -q

%build
%configure
make %{?_smp_mflags}

%install
rm -rf $RPM_BUILD_ROOT
%make_install

%files
%defattr(-,root,root,-)
%attr(755,root,root) /usr/bin/hello
%doc

%changelog

执行打包任务

rpmbuild -ba hello-1.0.0.spec

-bb 只编译二进制rpm包
-bs 只编译源码rpm包(src.rpm)
-ba 同时编译二进制和源码rpm包(src.rpm)
-bp 执行到%prep段,解开tar包然后把所有的补丁文件合并而生成一个完整的具最新功能的源文件

安装打包好的PRM包测试

rpm -ivh ~/rpmbuild/RPMS/x86_64/hello-1.0.0-1.el7.x86_64.rpm

hello
Hello World!

后记

本篇只是简略的介绍了一下RPM包的制作,实际上还有很多功能没有说明,可以慢慢了解。

以后遇到喜欢的工具但是没有提供RPM包,或者自己写的工具,可以方便的打包成RPM包了。

最后修改:2022 年 05 月 27 日
如果觉得我的文章对你有用,请随意赞赏