RPM打包浅析

RPM打包浅析

0:需要储备的知识及其目的:

需要要储备的知识

  • 对makefile有一定的了解。

  • C代码的编译及基本的C语法。

注:只需要能基本看懂第二节做好准备打包一个简单程序的内容即可。

教学目的

  • 能将自己编写的程序打包成RPM包,发布到网上供大家下载并安装使用。

一:RPM 基础知识

若要构建一个标准的 RPM 包,您需要创建 .spec 文件,其中包含软件打包的全部信息。然后,对此文件执行 rpmbuild 命令,经过这一步,系统会按照步骤生成最终的 RPM 包。

一般情况,您应该把源代码包,比如由开发者发布的以 .tar.gz 结尾的文件,放入 ~/rpmbuild/SOURCES 目录。将.spec 文件放入 ~/rpmbuild/SPECS 目录,并命名为 "软件包名.spec" 。当然, 软件包名 就是最终 RPM 包的名字。为了创建二进制(Binary RPM)和源码软件包(SRPM),您需要将目录切换至 ~/rpmbuild/SPECS 并执行:

 $ rpmbuild -ba NAME.spec

当执行此命令时,rpmbuild 会自动读取 .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 包通常用于审核和升级软件包。

rpmbuild 中,对上表中的每个宏代码都有对应的目录:

宏代码 名称 默认位置 用途
%_specdir Spec 文件目录 ~/rpmbuild/SPECS 保存 RPM 包配置(.spec)文件
%_sourcedir 源代码目录 ~/rpmbuild/SOURCES 保存源码包(如 .tar 包)和所有 patch 补丁
%_builddir 构建目录 ~/rpmbuild/BUILD 源码包被解压至此,并在该目录的子目录完成编译
%_buildrootdir 最终安装目录 ~/rpmbuild/BUILDROOT 保存 %install 阶段安装的文件
%_rpmdir 标准 RPM 包目录 ~/rpmbuild/RPMS 生成/保存二进制 RPM 包
%_srcrpmdir 源代码 RPM 包目录 ~/rpmbuild/SRPMS 生成/保存源码 RPM 包(SRPM)

如果某一阶段失败,请查看输出信息以了解失败原因,并根据需要修改 .spec 文件。

注:rpm中的宏值可通过下面的命令查询得到

$ rpm -E "{填入宏名}"
####例如
$ rpm -E "%{_rpmdir}"

二:做好准备打包一个简单程序

  • 创建简单的hello程序
$mkdir ~/rpmtest-01
$cd rpmtest-01
$vi hello.c
#include <stdio.h>
int main()
{
    printf("%s\n","hello world");
    return 0;
}
  • 编写makefile
$vi makefile
hello:hello.c
    gcc -o hello hello.c
clean:
    rm -f hello
install:
    install -m 755 hello $(INSTALL_DES)
  • 创建补丁文件
$ cd  ~/rpmtest-01
$ cp hello.c hello_src.c
$ vim hello.c //修改里面的内容
$ diff -u hello_src.c hello.c > hello.patch
  • 创建tar包
$ cd 
$ tar -czvf rpmtest-01.tar.gz rpmtest-01 

三:新建一个 .spec 文件

准备工作

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

$ sudo yum install rpm-build

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

$ sudo yum install rpmdevtools

模板和实例

模板

  • 如果您首次创建 .spec 文件,vim 或 emacs 会自动生成模板:

     $ cd 
     $ rpmdev-setuptree
     $ cp  ~/rpmtest-01.tar.gz   ~/rpmbuild/SOURCES
     $ cp  ~/rpmtest-01/hello.patch   ~/rpmbuild/SOURCES
     $ cd ~/rpmbuild/SPECS
     $ vim hello.spec
    
  • 示例:

    Name:    
    Version:    
    Release:    1%{?dist}
    Summary:    
    
    Group:    
    License:    
    URL:    
    Source0:    
    
    BuildRequires:  
    Requires:   
    
    %description
    
    
    %prep
    %setup -q
    
    
    %build
    %configure
    make %{?_smp_mflags}
    
    
    %install
    make install DESTDIR=%{buildroot}
    
    
    %files
    %doc
    
    
    
    %changelog
    

实例

这是将第二章的简单程序制作成一个RPM包

Name:   rpmtest
Version:    01  
Release:    1   
Summary:    rpm_test

License:    GPL 
URL:        www.baidu.com
Source0: rpmtest-01.tar.gz
Patch1: hello.patch
%description
this is a test for rpmbuild

%prep
%setup -q
%patch1 -p0 -b .hello

%build
make %{?_smp_mflags}


%install
make install  INSTALL_DES=/home/lhx/bin
mkdir -p /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64/home/lhx/
cp /home/lhx/hello /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64/home/lhx/


%files
/home/lhx/hello


%changelog
* Sun Dec 4 2016 Your Name <youremail@xxx.xxx> - 2.10-1
- build the program

优化实例

#%define bin_dest  %(echo $HOME)/bin
%define bin_dest  %{_sbindir}
Name:   rpmtest
Version:    01  
Release:    1   
Summary:    rpm_test

License:    GPL 
URL:        www.baidu.com
Source0: rpmtest-01.tar.gz
Patch1: hello.patch
%description
this is a test for rpmbuild

%prep
%setup -q
%patch1 -p0 -b .hello

%build
make %{?_smp_mflags}


%install
mkdir -p  %{bin_dest}
sudo make install INSTALL_DES=%{bin_dest}
mkdir -p %{buildroot}%{bin_dest}
cp %{bin_dest}/hello %{buildroot}%{bin_dest}


%files
%{bin_dest}/hello


%changelog
* Sun Dec 4 2016 Your Name <youremail@xxx.xxx> - 2.10-1
- build the program

四:SPEC文件综述

参数 参数意义
Summary 一行简短的软件包介绍。请使用美式英语。请勿在结尾添加标点!
Name 本软件的软件名称 (最终会是 RPM 档案的档名构成之一)
Version 本软件的版本 (也会是 RPM 档名的构成之一)
Release 这个是该版本打包的次数说明 (也会是 RPM 档名的构成之一)。
License 这个软件的授权模式,我们是使用 GPL 啦!
Url 这个原始码的主要官方网站
Source 源文件的文件名,文件名用于查找 SOURCES 目录
Patch 就是作为补丁的 patch file 啰!
BuildRoot 设定作为编译时,该使用哪个目录来暂存中间档案 (如编译过程的目标档案/链接档案等档)。
BuildRequires 编译软件包所需的依赖包列表,以逗号分隔。此标签可以多次指定。编译依赖 不会 自动判断,所以需要列出编译所需的所有依赖包。常见的软件包可省略,例如 gcc
Requires 安装软件包时所需的依赖包列表,以逗号分隔。请注意, BuildRequires 标签是编译所需的依赖,而 Requires 标签是安装/运行程序所需的依赖。
%prep 打包准备阶段执行一些命令(如,解压源码包,打补丁等),以便开始编译。
%build 包含构建阶段执行的命令,构建完成后便开始后续安装。
%install 包含安装阶段执行的命令
%files 需要被打包/安装的文件列表。
%changelog RPM 包变更日志。请使用示例中的格式。

五:SPEC文件剖析

%prep部分

"%autosetup" 命令用于解压源码包。可用选项包括:

  • -n *name* : 如果源码包解压后的目录名称与 RPM 名称不同,此选项用于指定正确的目录名称。例如,如果 tarball 解压目录为 FOO,则使用 "%autosetup -n FOO"。
  • -c *name* : 如果源码包解压后包含多个目录,而不是单个目录时,此选项可以创建名为 name 的目录,并在其中解压。

如果使用 "%setup" 命令,通常使用 -q' 抑止不必要的输出。

如果需要解压多个文件,有更多 %spec 选项可用,这对于创建子包很有用。常用选项如下:

-a number 在切换目录后,只解压指定序号的 Source 文件(例如 "-a 0" 表示 Source0)
-b number 在切换目录前, 只解压指定序号的 Source 文件(例如 "-b 0" 表示 Source0)
-D 解压前,不删除目录。
-T 禁止自动解压归档。

%prep 部分:%patch 命令

"%patch0" 命令用于应用 Patch0(%patch1 应用 Patch1,以此类推)。Patches 是修改源码的最佳方式。常用的 "-pNUMBER" 选项,向 patch 程序传递参数,表示跳过 NUM 个路径前缀。

%files 部分

您应该列出该软件包拥有的所有文件和目录。尽量使用宏代替目录名,查看宏列表 Packaging:RPMMacros(例如:使用 %{_bindir}/mycommand 代替 /usr/bin/mycommand)。

六:运行结果

  • 将tar包移入~/rpmbuild/SOURCE/文件夹下

  • 编译rpm包

$cd ~/rpmbuild/SPECS
$rpmbuild -ba hello.spec 
执行(%prep): /bin/sh -e /var/tmp/rpm-tmp.WN1NeY
+ umask 022
+ cd /home/lhx/rpmbuild/BUILD
+ cd /home/lhx/rpmbuild/BUILD
+ rm -rf rpmtest-01
+ /usr/bin/tar -xf -
+ /usr/bin/gzip -dc /home/lhx/rpmbuild/SOURCES/rpmtest-01.tar.gz  <===>解压源码
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd rpmtest-01               <====> 进入源码文件夹
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ echo 'Patch #1 (hello.patch):'
Patch #1 (hello.patch):
+ /usr/bin/cat /home/lhx/rpmbuild/SOURCES/hello.patch
+ /usr/bin/patch -p0 -b --suffix .hello --fuzz=0    <==打补丁==>对应 %patch1 -p0 -b .hello 
patching file hello.c
+ exit 0
执行(%build): /bin/sh -e /var/tmp/rpm-tmp.bitRL1
+ umask 022
+ cd /home/lhx/rpmbuild/BUILD
+ cd rpmtest-01
+ make -j3              <====>对应 make %{?_smp_mflags},
gcc -o hello hello.c    <====> 对应makefile中的规则
+ exit 0
执行(%install): /bin/sh -e /var/tmp/rpm-tmp.C3O4R5
+ umask 022
+ cd /home/lhx/rpmbuild/BUILD
+ '[' /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64 '!=' / ']'
+ rm -rf /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64
++ dirname /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64
+ mkdir -p /home/lhx/rpmbuild/BUILDROOT
+ mkdir /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64
+ cd rpmtest-01
+ mkdir -p /usr/sbin          <====>对应 mkdir -p  %{bin_dest}
+ sudo make install INSTALL_DES=/usr/sbin      <===>对应sudo make install INSTALL_DES=%{bin_dest}
[sudo] password for lhx: 
install -m 755 hello /usr/sbin    <====>对应 sudo make install INSTALL_DES=%{bin_dest}
+ mkdir -p /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64/usr/sbin
+ cp /usr/sbin/hello /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64/usr/sbin
+ /usr/lib/rpm/find-debuginfo.sh --strict-build-id -m --run-dwz --dwz-low-mem-die-limit 10000000 --dwz-max-die-limit 110000000 /home/lhx/rpmbuild/BUILD/rpmtest-01
extracting debug info from /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64/usr/sbin/hello
dwz: Too few files for multifile optimization
/usr/lib/rpm/sepdebugcrcfix: Updated 0 CRC32s, 1 CRC32s did match.
+ '[' '%{buildarch}' = noarch ']'
+ QA_CHECK_RPATHS=1
+ case "${QA_CHECK_RPATHS:-}" in
+ /usr/lib/rpm/check-rpaths
+ /usr/lib/rpm/check-buildroot
+ /usr/lib/rpm/redhat/brp-compress
+ /usr/lib/rpm/redhat/brp-strip-static-archive /usr/bin/strip
+ /usr/lib/rpm/brp-python-bytecompile /usr/bin/python 1
+ /usr/lib/rpm/redhat/brp-python-hardlink
+ /usr/lib/rpm/redhat/brp-java-repack-jars
处理文件:rpmtest-01-1.x86_64
Provides: rpmtest = 01-1 rpmtest(x86-64) = 01-1
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: libc.so.6()(64bit) libc.so.6(GLIBC_2.2.5)(64bit) rtld(GNU_HASH)
处理文件:rpmtest-debuginfo-01-1.x86_64
Provides: rpmtest-debuginfo = 01-1 rpmtest-debuginfo(x86-64) = 01-1
Requires(rpmlib): rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1 rpmlib(CompressedFileNames) <= 3.0.4-1
检查未打包文件:/usr/lib/rpm/check-files /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64
写道:/home/lhx/rpmbuild/SRPMS/rpmtest-01-1.src.rpm
写道:/home/lhx/rpmbuild/RPMS/x86_64/rpmtest-01-1.x86_64.rpm
写道:/home/lhx/rpmbuild/RPMS/x86_64/rpmtest-debuginfo-01-1.x86_64.rpm
执行(%clean): /bin/sh -e /var/tmp/rpm-tmp.pERCJS
+ umask 022
+ cd /home/lhx/rpmbuild/BUILD
+ cd rpmtest-01
+ /usr/bin/rm -rf /home/lhx/rpmbuild/BUILDROOT/rpmtest-01-1.x86_64
+ exit 0

七:安装/测试/实际查询 /卸载

[lhx@localhost x86_64]$ sudo rpm -ivh rpmtest-01-1.x86_64.rpm 
准备中...                          ################################# [100%]
正在升级/安装...
1:rpmtest-01-1                     ################################# [100%]

[lhx@localhost x86_64]$ rpm -qi rpmtest 
Name        : rpmtest
Version     : 01
Release     : 1
Architecture: x86_64
Install Date: 2020年05月07日 星期四 23时20分44秒
Group       : Unspecified
Size        : 7136
License     : GPL
Signature   : (none)
Source RPM  : rpmtest-01-1.src.rpm
Build Date  : 2020年05月07日 星期四 23时09分57秒
Build Host  : localhost
Relocations : (not relocatable)
URL         : www.baidu.com
Summary     : rpm_test
Description :
this is a test for rpmbuild

[lhx@localhost x86_64]$ hello
hello redflag

[lhx@localhost x86_64]$ sudo yum erase rpmtest.x86_64

八:参考资料

上一篇:Linux在线安装JDK1.8


下一篇:MySQL笔记_02_MySQL5.7二进制自动化安装脚本