荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: cbi@bbs.pku.edu.cn (土豆|天黑黑,心冷冷), 信区: Linux
标  题: 精通RPM之--制作篇 zz
发信站: 北大未名站 (Sat Nov 29 02:19:07 2003)
转信站: SZU!news.ccie.net.cn!news.happynet.org!PKU

制作篇(上)
(雨亦奇 赵建利 2001年12月05日 14:24)

连载系列

要想制作一个RPM格式的软件包,需要编写软件包描述文件。其标准命名格式为:软件名-版
本号-释出号.spec,这个文件,详细描述了有关该软件包的诸多信息,如软件名,版本,类别
,说明摘要,创建时要执行什么指令,安装时要执行什么操作,以及软件包所要包含的文件等
等。有了这个文件,RPM就可以制作出相应的包裹文件来。

下面以我制作小赵编辑器LZE的软件包(lze-6.0-2.i386.rpm)为例,详细说明一下软件包描
述文件的书写。其描述文件为lze-6.0-2.spec,该文件内容如下:(用nl -ba命令列出,每行
开头的数字为所在行在文件中的行号)
1 # 文件名称: lze-6.0-2.spec
2 # 文件功能: lze软件包描述信息
3 # 文件作者: 纵横软件制作中心雨亦奇 国防大学研究生二队赵建利
4 # 修改时间: 2001.10.19
5
6 Name: lze
7 Version: 6.0
8 Release: 2
9 Summary: 小赵全屏幕中英文多窗口多功能编辑器(LINUX/UNIX系统适用)
10 Group: Applications/Editors
11 License: Share
12 Vendor: 纵横软件制作中心
13 Packager: 雨亦奇(zhsoft@371.net)
14 Source: http://zhsoft.myetang.com/lze-6.0-2.src.tgz
15 Prefix: /usr
16 Requires: /bin/sh
17 Provides: lze-edit
18
19 %description
20 小赵编辑器,是为使用SCO UNIX,LINUX多用户系统的广大用户专门设计的全屏幕多窗
21 口中英文多功能编辑器。
22 它主要有以下十大特点:1.全屏幕菜单操作。2.显示方式多样。3.块操作丰富。4.十
23 字制表功能强大。5.多窗口操作灵活自如。6.文件操作功能齐全。7.解释输出功能独
具特
24 色。8.自带中文输入法(增强五笔和增强拼音),实用方便。9.十六进制编辑功能,
如虎
25 添翼。10.即时翻译,按到即译。
26 总之,小赵编辑器会成为您在UNIX,LINUX系统上编制程序和书写一般性文稿的好帮手

27 它将在工作中助您一臂之力,轻松上阵,游刃有余!
28
29 %prep
30 echo "预处理脚本程序(prep)开始执行"
31 %setup
32
33 %build
34 echo "编译连接脚本程序(build)开始执行"
35 make
36
37 %install
38 echo "安装脚本程序(install)开始执行"
39 make install
40
41 %clean
42 echo "建包结束后清理脚本程序(clean)开始执行"
43
44 %pre
45 echo "安装前执行脚本程序(pre)开始执行"
46
47 %post
48 echo "安装后执行脚本程序(post)开始执行"
49
50 %preun
51 echo "卸载前执行脚本程序(preun)开始执行"
52
53 %postun
54 echo "卸载后执行脚本程序(postun)开始执行"
55
56 %veryfiscript
57 echo "软件包校验脚本程序(verifyscript)开始执行"
58
59 %triggerin -- xiuwu
60 echo "软件包安装时触发脚本程序(triggerin)开始执行"
61
62 %triggerun -- yuntaishan < 2.0
63 echo "软件包卸载前触发脚本程序(triggerun)开始执行"
64
65 %triggerpostun -- dapubu
66 echo "软件包卸载后触发脚本程序(triggerpostun)开始执行"
67
68 %files
69 %defattr (-,root,root)
70 %config /etc/funkey.def
71 %config /etc/inputme.def
72 %doc /usr/doc/lze-6.0/README
73 %doc /usr/doc/lze-6.0/LICENSE
74 /usr/bin/lze
75 /usr/bin/lzeime.py
76 /usr/bin/lzeime.wb
77 /etc/wbzc.dat
78
79 %changelog
80 * Tue Aug 18 1998 雨亦奇
81 - 内置拼音,五笔输入法
82 * Fri May 01 1998 雨亦奇
83 - 增加多窗口操作
84 * Mon Mar 24 1997 雨亦奇
85 - 增加块操作命令
86

该描述文件包括以下几方面的内容:

一、注释行
见第1-4行。
它以#号开头,起注解作用,可帮助用户理解所写的内容,但对软件包的生成不起任何作用。
此文件中,注释行集中在文件首部。实际上,它可位于描述文件的任何位置。

二、文件头
见第6-17行。
文件头描述软件包的基本信息,它包含若干个域,其中有必选的域,也有可选的域。一个域
占用一行,其描述格式为:
域名 : 域值
注意: 域名不分大小写,并且域值不能为空。
文件头必选域有以下六个:

1. Name :
此域定义软件名。

2. Version :
此域定义版本号。仅当软件较以前有较大改变时才增加版本号。注: 版本号中不能含减号
(-)字符。

3. Release :
此域定义释出号。若软件较以前改变较小,则仅增加释出号,不改变版本号。注: 释出号中
亦不能含减号(-)字符。
RPM利用上述的Name(软件名),Version(版本号),Release(释出号)及体系号来命名软件包
,如本例输出的包裹文件名为lze-6.0-2.i386.rpm。

4. Summary :
此域定义软件包简介,为一句话说明。

5. Group :
此域定义软件所属类别,详见<<精通RPM之五--查询篇>>,本例的Applications/Editors表
示本软件属"应用/编辑器"类。

6. License :
此域定义软件适用的许可证或版权规则。该域也可用Copyright(版权)来定义,二者同意。
许可证具体有: GPL(通用公共许可证,自由软件适用),BSD,MIT,Public Domain(公共域
),Distributable(贡献),Commercial(商业),Share(共享)等。

文件头可选的域包括如下几类:
1. 基本信息

1.1 Vendor :
此域定义软件的供应商(销售商)。

1.2 Distribution :
此域定义软件所属的发行版,这是软件包制作者自己的分类。通常,一个发行版由若干个软
件包构成。如我想做一个名为“熊猫'95”的发行版,则其中每个软件包(如竹叶95)的描述
文件都应有这么一行:
Distribution : 熊猫'95

1.3 Icon :
此域指定软件包所用的图标文件名。此文件为GIF或XPM格式,必须存放在RPM的
%_sourcedir(源码目录)宏所指示目录下,默认为/usr/src/dist/SOURCES。RPM本身并不使
用图标,但它将图标文件内容存贮到包裹文件中,安装时亦存贮到RPM数据库中。此图标可
被图形界面的RPM包管理工具使用,用以改善界面效果,增加可视性。如下例指示软件包使
用panda.xpm作为图标:
Icon : panda.xpm

1.4 Packager :
此域定义打包者,亦即建立此软件包的人或公司。书写格式是:
打包者的名字 <电子信箱或相关网页>
请参考描述文件第13行。

1.5 Serial :
此域定义软件序列号,也可使用域名Epoch。软件序列号为一整数,由打包者指定,它应随着
版本号的增加而不断增加,并且始终保持数值的唯一。软件序列号可被用来说明软件包之
间的依赖关系。下例指定软件包序列号为4:
Serial : 4
或用:
Epoch : 4

1.6 URL :
此域定义包含打包软件有关信息的网页地址。如:
URL : http://devplanet.fastethernet.net/gxedit.html

2. 依赖相关
依赖是RPM用来描述软件包之间关系的。一个软件包依赖的东西RPM称作功能,它可以是真
实存在的软件包,也可以是虚拟的软件包(虚包)。虚包没有版本号。
依赖相关的域有:

2.1 Provides :
此域定义软件包提供的功能,可重复多行。其描述格式为:
Provides : 功能1 [,功能2] ...

注: []所括为可选项,多个功能之间以逗号或空格分隔。
软件包所提供的功能一般是以虚包形式存在的共享库。当有多个软件包均提供相同的服务
时,常用虚包来表示其服务。如,一个邮件客户端软件允许用户使用不同的看信方式(文本
形式,HTML形式等),可以要求任何一个看信程序必须提供mail-reader虚包。这样,看信程
序的描述文件应有这么一行:
Provides : mail-reader
如此它才能被邮件客户端使用。

2.2 Requires :
此域定义软件包所需的功能,可重复多行。其描述格式为:
Requires : 功能1 [比较符1 [序列号1:]版本号1[-释出号1]] [,功能2 [比较符2 [序列
号2:]版本号2[-释出号2]]] ...

其中: * []所括为可选项;
* 比较符可使用<(小于),>(大于),=(等于),>=(大于等于)或<=(小于等于);
* 序列号不选时,RPM默认为0;
* 功能之间的逗号可选,也可使用空格进行分隔。
例子:Requires: aaa, bbb >= 3.0, ccc < 2:5.0-1
注: 本例定义生成的包在安装时需要系统有如下功能:
(1) aaa(系统中已安装aaa包,或者已安装软件包中有软件包提供aaa虚包);
(2) bbb包已安装且版本要求大于等于3.0;
(3) ccc包已安装且版本要求小于序列号为2,版本号为5.0且释出号为1。
RPM在进行版本比较时,执行比较的顺序是; 先版本号,再释出号,最后比较序列号。通过比
较,确定哪个版本较新,哪个版本较老。

2.3 Conflicts :
此域定义有哪些功能与本软件包相冲突(不能共存)。此域亦可在描述文件中书写多次。其
描述格式形同Requires域,为:
Conflicts : 功能1 [比较符1 [序列号1:]版本号1[-释出号1]] [,功能2 [比较符2 [序列
号2:]版本号2[-释出号2]]] ...

其中: * []所括为可选项;
* 比较符可使用<(小于),>(大于),=(等于),>=(大于等于)或<=(小于等于);
* 序列号不选时,RPM默认为0;
* 功能之间的逗号可选,也可使用空格进行分隔。
举个例子:
Conflicts : xxx=1:2.0 yyy>=3.0
注: 本例阐明生成的包冲突的功能有:
(1) 当系统中xxx包版本等于序列号为1且版本号为2.0时;(2) 当系统中yyy包版本大于等
于3.0时。
*** 依赖关系的自动实现 ***
一般情况下,当RPM建立一个软件包时,它要执行/usr/lib/rpm目录下的两个小程序。一个
是find-requires,用于查找软件包所需的共享库,这些库将以虚包的形式加入到该软件包
所需的功能(Requires)之中。另一个是find-provides,它用于查找软件包所提供的共享库
,这些库将以虚包的形式加入到该软件包所提供的功能(Provides)之中。这两个程序都是
SHELL程序,代码量虽小,但确实帮了软件包制作者一个大忙--不必劳心费神地自己写这样
的依赖关系了,因为程序均自动完成了。
下面三个域用于指示RPM是否执行这两个程序。

2.4 Autoreq :
此域用于指示RPM是否自动查找软件所需的共享库。仅当域值为no或0时,RPM不执行
find-requires程序,否则均执行该程序。

2.5 Autoprov :
此域用于指示RPM是否自动查找软件提供的共享库。仅当域值为no或0时,RPM不执行
find-provides程序,否则均执行该程序。

2.6 Autoreqprov :
此域用于指示RPM是否自动查找软件所需的共享库与其提供的共享库。仅当域值为no
或0时,RPM不执行find-requires与find-provides两个程序。此域相当于同时设定
Autoreq
与Autoprov域值为指定之值。
注: 上述三个域在描述文件中,它们之间因为顺序的不同而结果会有所不同,一般以最后一
个为准。如:
Autoreq : yes
Autoreqprov : no
Autoprov : yes

注: 本例虽然第一行允许执行find-requires,但第二行又不允许find-requires与
find-provides两个程序运行,而第三行允许find-provides运行,所以依照执行顺序,结果
为不允许执行find-requires,而允许执行find-provides。
又如:
Autoreq : no
Autoreqprov : yes
Autoprov : no

注: 本例的结果为允许执行find-requires,而不允许执行find-provides。

3. 系统相关
RPM制作软件包时,可以为其指定适用的CPU体系或操作系统,也可为其指定不适用的CPU体
系或操作系统,这样,当RPM发现当前的CPU体系或操作系统与软件包要求的不兼容时,将中
止软件包的制作。RPM默认的当前CPU体系由宏%_arch定义,一般为i386。RPM默认的当前操
作系统由宏%_os定义,一般为linux。读者可以通过查看/usr/lib/rpm/macros宏定义文件
得到。
下面四个域说明软件包的适用范围:

3.1 Excludearch :
此域定义软件包不适用的体系。RPM可选的体系名请参见/usr/lib/rpm/rpmrc文件中的
arch_canon项目。
软件包不适用于某个体系,可能有两方面的原因。一是该软件还没有移植到所定义的体系
上;二是该软件含有特定的机器码(汇编语言),它与别的体系不兼容。
此域描述格式为:
Excludearch : 体系1 [体系2] ...

注: []所括为可选项,各体系之间以空格分隔。
如果当前体系在此域值之中,则RPM制作软件包时将报错退出,请看下面的例子。
在lze-6.0-2.spec文件头部分加入一行:
Excludearch : i386
再运行建包命令rpm -bb(<<精通RPM之七--制作篇(下)>>将讲到):
# rpm -bb lze-6.0-2.spec
Architecture is excluded: i386
#

由上看出,RPM提示了“体系不适用: i386”的错误。

3.2 Exclusivearch :
此域定义软件包适用的体系。其描述格式与Excludearch类似:
Exclusivearch : 体系1 [体系2] ...

注: []所括为可选项,各体系之间以空格分隔。
假如在lze-6.0-2.spec文件头加入一行:
Exclusivearch : i386 sparc
再运行建包命令将会怎么样:
# rpm -bb lze-6.0-2.spec
Executing: %prep
预处理脚本程序(prep)开始执行
Executing: %build
编译连接脚本程序(build)开始执行
Executing: %install
安装脚本程序(install)开始执行
Processing files: lze
Finding Provides: (using /usr/lib/rpm/find-provides)...
Finding Requires: (using /usr/lib/rpm/find-requires)...
Provides: lze-edit
PreReq: /bin/sh
Requires: /bin/sh ld-linux.so.2 libc.so.6 libc.so.6(GLIBC_2.0)
libc.so.6(GLIBC_2.1)
Wrote: /usr/src/dist/RPMS/i386/lze-6.0-2.i386.rpm
#

看,此次建包(lze-6.0-2.i386.rpm)成功了,因为当前的体系(i386)正好适用。

3.3 Excludeos :
此域定义软件包不适用的操作系统。RPM可选的操作系统请参考文件/usr/lib/rpm/rpmrc
中的os_canon项目。
其描述格式为:
Excludeos : 操作系统1 [操作系统2] ...

注: []为可选项,操作系统之间以空格分隔。例如:
Excludeos : irix aix solaris
注: 如将此行加入到lze的描述文件中,则它会指示RPM不在irix,aix,solaris这三个操作
系统上建立lze软件包。如果当前操作系统是三者之一,则RPM会报错并中止软件包的制作

如:
# rpm -bb lze-6.0-2.spec
OS is excluded: Solaris
#

3.4 Exclusiveos :
此域定义软件包适用的操作系统。其描述格式为:
Exclusiveos : 操作系统1 [操作系统2] ...
注: []为可选项,操作系统之间以空格分隔。例如:
Exclusiveos : linux solaris

4. 目录相关
4.1 Prefix :
此域定义可重定位的目录前缀,可在描述文件中书写多次。其描述格式为:
Prefix : 目录前缀1 [目录前缀2] ...

注: []为可选项,各目录前缀之间均以空格分隔。例如:
Prefix : /usr /etc
它也可写作:
Prefix : /usr
Prefix : /etc
RPM利用可重定位的目录前缀,实现了软件包的重定位安装,使软件中的文件不必固定在某
个绝对位置,这种做法很好。LZE软件包描术文件lze-6.0-2.spec中就定义了一个可重定位
的前缀/usr(见第15行),这样,安装时就可将该包中在/usr目录下的文件重定位到用户指定
的目录,如:
# rpm -i --prefix /tmp lze-6.0-2.i386.rpm
#
或者:
# rpm -i --relocate /usr=/tmp lze-6.0-2.i386.rpm
#
注: 此命令安装lze包,将其中含/usr重定位目录前缀的文件定位到/tmp目录。如包中
的/usr/bin/lze文件安装后,因重定位而成了/tmp/bin/lze。(RPM安装命令使用方法请参
考<<精通RPM之二--安装篇>>)

4.2 Buildroot :
此域定义的是软件包所包含的文件共有的根目录,此根目录仅供RPM建立软件包时使用。即
当RPM建立软件包时,将设定此目录为根(调用chroot函数),提取所需文件,生成软件包。
例如: 当Buildroot设定为/tmp时,对于LZE包描述文件中所包含的/usr/bin/lze文件,RPM
实际打包的则是/tmp/usr/bin/lze,但对生成的包查询后可以发现:原文件名并未改变,还
是/usr/bin/lze。
如此说来,这就很有意思了。一般用户通过设定Buildroot,也可以象超级用户(root)那样
自由地建立各种各样的软件包了,即使包中有那些唯有超级用户才可以操作的目录或文件
。安装这样的包与安装由超级用户建立的包,是没有什么分别的。
此域的描述格式很简单:
Buildroot : 目录
如,上例可定义为:
Buildroot : /tmp

5. 源码相关
下列四个域均是为制作源码包而设计的。源码包里有什么?用户可以通过查询包的文件列
表得到,命令是“rpm -qpl 源码包文件”(请参阅<<精通RPM之五--查询篇>>有关内容)。
一般情况下,源码包里有这么四类文件: 一是程序源码(SOURCE),二是源码补丁(PATCH),三
是软件包描述文件,四是图标文件(ICON)。通过安装源码包,用户可以轻松地实现现场编译
、连接和应用,同时更方便了软件开发者与软件包制作者:他们维护程序容易了,并且维护
过后可以很快地生成执行代码包与源码包。这,也是所有人钟爱RPM的重要原因之一。

5.1 Source :
此域定义RPM打包时要包含的程序源码文件。这些文件一般先用tar命令打包,然后再用
gzip压缩。一个描述文件中可包含多个Source域,当有多个这样的域时,需要进行编号:第
1个编为Source0(也可直接用Source),第2个编为Source1,第3个编为Source2等等。此域的
描述格式为:
Source[编号] : 源码文件

注: []所括为可选项。具体用法如:
Source0 : lze-6.0-2.tar.gz
Source1 : lzeime-wb-6.0-2.tar.gz
Source2 : lzeime-py-6.0-2.tar.gz
Source3 : lze-lib-6.0-2.tar.gz
注: 此域域值可以采用URL(统一资源定位)的形式,如LZE描述文件第14行。采用这种形式
,主要是给其它用户提供该源码的位置信息。在RPM制作源包时,它提取的是最后的文件名
lze-6.0-2.tar.gz,而不是http://zhsoft.myetang.com/lze-6.0-2.tar.gz(URL前面的内
容被RPM忽略了)。

5.2 NoSource :
在上例中,假如在打包时不想包含Source1与Source2定义的文件,那该怎么办?
办法之一是将其所在行删除掉;
办法之二是将其所在行注释掉(即所在行前面加#号);
办法之三就是定义Nosource域,此域可重复。其描述格式为:
NoSource : 源码域编号

本例可写作:
NoSource : 1
NoSource : 2
注: 其中的1与2为编号,表示Source1和Source2。
注意: 如果软件包描述文件中没有NoSource域,则RPM生成的源码包名字格式为"软件名-版
本号-释出号.src.rpm"。如果使用了NoSource域,则RPM生成的源码包名字格式为"软件名
-版本号-释出号.nosrc.rpm"(单从名字就可看出源码包包含的文件不完整)。

5.3 Patch :
Patch的本义是补丁,用在这里指的是源程序的补丁,它是用diff命令比较新老源程序所产
生的输出(命令为“diff -Nur 旧文件 新文件 >补丁文件”),而系统中的patch命令又可
利用此输出将老版本的源程序升级为新版本。
此域定义RPM制作源码包时所要包含的补丁文件,该文件的命名建议用"软件名-版本号.补
丁功能.patch"的格式。一个软件包描述文件中可有多个Patch域,当有多个这样的域时,也
需要象Source域那样进行编号(注:第1个域编为Patch0,也可省略0,用Patch)。
此域的描述格式为:
Patch[编号] : 源码补丁文件

注: []所括为可选项。具体用法如:
Patch0 : blather-4.5-bugfix.patch
Patch1 : blather-4.5-config.patch
Patch2 : blather-4.5-somethingelse.patch
注: 此域的域值也可以象Source域一样,采用URL的形式,RPM仅提取其中的文件名供其使用


5.4 NoPatch :
此域的功能类似NoSource,其定义的编号对应的补丁文件RPM不作打包处理。此域在描述文
件中可重复出现。如上例,若不想让源码包包含Patch0与Patch2域所指示的补丁文件,则可
在描述文件写上这么两行:
NoPatch : 0
NoPatch : 2
注意: 如果软件包描述文件中没有NoPatch域,则RPM生成的源码包名字格式为"软件名-版
本号-释出号.src.rpm"。如果使用了NoPatch域,则RPM生成的源码包名字格式为"软件名-
版本号-释出号.nosrc.rpm"(单从名字就可看出源码包包含的文件不完整)。

三、功能段
见第19-86(即文件头以下的部分)。
何谓功能段?可以这么说,功能段是描述软件包的重要数据和操作指令的段落,它包括段名
与段内容两部分。没有功能段,RPM便制作不出任何包裹文件。功能段的段名都是以百分号
(%)开始的,占用一行。功能段的段内容范围是这样界定的:它从该功能段段名下一行开始
到下一个功能段段名的前一行或到描述文件结束。如LZE描述文件,%description段是从第
19行到第28行(%prep段从第29行开始),第19行为段名,第20-28行为段内容。而%prep段是
从第29行到第32行(第33行%build段开始),其段名在第29行,段内容在第30-32行。另外要
注意的是,各个功能段的位置是自由的,可放在文件头以下的任何位置,不必拘泥某一固定
位置。
必选的功能段
描述文件中,必选的功能段有:

1. %description
本段是描述段,段的内容是对软件包进行较为详细的介绍,不象文件头的Summary域仅用一
句话说明。介绍的文本形式自由,可任意换行,不受限制。具体请参见LZE描述文件第
20-27行。
本段段名描述格式是:
%description [子包选项]

其中,子包选项的格式为:[-n] 子包名
注: []所括为可选项。

三种形式的描述段段名:
(1) 段名格式为“%description”时:
本功能段描述的内容是关于父包的。父包也可叫作主软件包,它用软件名来命令,其名字格
式是:软件名-版本号-释出号.体系.rpm。如:lze-6.0-2.i386.rpm。
(2) 段名格式为“%description 子包名”时:
本功能段描述的内容是关于子包的。子包选项中没有-n选项时,子包是用软件名加子包名
的形式命名,格式为: 软件名-子包名-版本号-释出号.体系.rpm。如分成两个子包的LZE软
件:lze-bin-6.0-2.i386.rpm(执行程序包),lze-config-6.0-2.i386.rpm(配置文件包)。
(3) 段名格式为“%description -n 子包名”时:
本功能段描述的内容也是关于子包的。当子包选项中有-n选项时,子包直接采用子包名的
形式命名。它不包含软件名,命名格式为: 子包名-版本号-释出号.体系.rpm。如分成两个
子包的LZE软件: bin-6.0-2.i386.rpm(执行程序包),config-6.0-2.i386.rpm(配置文件包
)。注意:这种类型的子包内容通常是可被其它软件包共用的函数库,如果专用,则尽量不要
采用这样形式来定义子包。

2. %files
本段是文件段,它定义的是软件包需要包含哪些文件。本段通常放在描述文件尾部,以便于
添加文件名,便于编辑。
本段段名描述格式为:
%files [子包选项] [-f 文件名]

注: []所括为可选项。
当没有任何选项时,本段内容定义的是父包要打包的文件列表;
当有子包选项时,本段内容定义的则是子包要打包的文件列表;
当选择-f选项时,RPM除了从文件段读取打包文件列表外,还将从指定的文件中读取要打包
的文件列表。指定的文件中,一个文件名占用一行。此选项方便了软件包制作者,他们可以
通过程序自动产生有关软件的文件列表,并将其写入到一个特定的文件中,这样制作软件包
时,只需引用一下这个文件,RPM就会自动从这个文件中读取文件名并将其加入包中。如果
没有此选项,软件包制作者只能在文件段里,将要打包的文件名一个一个写进去,有点麻烦


文件段的内容格式为:
[修饰符1 [修饰符2] ...] 文件名
其中:修饰符是可选的,一个文件可以有多个修饰符,文件名必须以/开头(绝对路径形式)。

修饰符有以下几类:

(1) 文件相关
* %doc :
此修饰符设定文件类型为说明文档(参见LZE描述文件第72,73行);
* %config :
此修饰符设定文件类型为配置文件(参见LZE描述文件第70,71行);
* %config(missingok) :
此修饰符设定文件类型为配置文件,且此文件可丢失。即使丢失了,RPM在卸载软件包时并
不认为这是个错误,并不报错。
此修饰符通常用于那些软件包安装后建立的符号连接文件,如/etc/rc.d/rc2.d/S55named
等。此类文件在软件包卸载后可能需要删除,所以丢失了也不要紧。
* %config(noreplace) :
此修饰符设定文件类型为配置文件,且如果安装时系统中有同名的文件,则软件包中的这个
文件将换个名字安装,其文件名后缀加个.rpmnew。(如果不用此修饰符,则安装时RPM若发
现有同名文件,则RPM会将系统中的这个文件换个名字,其后缀加上.rpmorig,而软件包中的
文件则还用原来的名字。)在软件包卸载时,系统中的同名文件被RPM换个名字保存起来,其
后缀加上了.rpmsave。
如描述文件的文件段中定义了这么一行:
%config(noreplace) /etc/hello
则制成的包在安装时,若系统中已有此文件/etc/hello,则RPM会提示:
warning: /etc/hello created as /etc/hello.rpmnew
这表明包中的/etc/hello文件被创建为/etc/hello.rpmnew文件了。
如果卸载这个软件包,则系统中的/etc/hello将会改名为/etc/hello.rpmsave。
* %ghost :
此修饰符所修饰的文件,其内容不被包含到软件包中。这样的文件一般是日志文件(log
file)一类的文件,其文件属性(文件名,属主,属组等)很重要,但是文件内容并不重要。用
此修饰符后,RPM仅将其文件属性加入包中。
* %attr :
此修饰符设定文件的属性信息,使用格式为:
%attr(权限,属主,属组)
注: 权限常用数字形式(八进制),属主和属组可以是数字,也可以是字符串。如果文件的权
限,属主和属组想使用系统默认值,则可用减号(-)表示它。
如下例采用两个修饰符,定义/etc/funkey.def文件的权限为755,属主默认,属组为root,类
型为配置文件:
%attr(755,-,root) %config /etc/funkey.def
* %verify :
此修饰符设定文件需要校验的那些属性。这些属性有:owner(属主),group(属组),mode(权
限),md5(MD5检查和),size(大小),maj(主设备号),min(从设备号),symlink(符号连接
),mtime(最后修改时间)。
此修饰符使用格式为:
%verify([not] owner group mode md5 size maj min symlink mtime)
注: not可选。当选用not时,表明需要校验除选定属性以外的那些属性。
如下例指示RPM校验/dev/ttyS0文件时,要校验其权限,MD5检查和,大小,主设备号,从设备
号,符号连接和最后修改时间共七项属性信息:
%verify(mode md5 size maj min symlink mtime) /dev/ttyS0
这也可以采用not选项来实现,因为除去属主owner和属组group两项属性,剩下的就是需要
校验的属性了:
%verify(not owner group) /dev/ttyS0

(2) 目录相关
* %docdir :

此修饰符定义说明文档前缀,这样,后面所有含指定文件名作为前缀的文件,RPM打包时会将
其类型统一设定为说明文档。
例如某描述文件的文件段中有这么三行:
/root/readme
%docdir /root
/root/mydoc.txt

此例指明/root为说明文档的前缀,因为/root/mydoc.txt在%docdir的下一行,所以RPM打包
时会设定此文件的类型为说明文档。而/root/readme文件则不做此设定,因为它在
%docdir定义之前。
通过此修饰符,用户可以很方便地设定说明文档一类的文件,因为它们通常固定在某个目录
下面,有着共同的前缀。
* %dir :
RPM在制作软件包时,如果要打包的文件是个目录,那么RPM会将该目录下面的所有文件包含
到软件包中。(注意:如果要打包的文件是个符号连接,此符号连接又指向一个目录,则RPM
并不会将其视作目录,只会把它当为普通文件处理。)如果仅想将这个目录名包含到软件包
中,制作者用此修饰符修饰一下这个目录名就行了。
如: /etc是个系统目录,其下有多个文件,如果想将其均加入包中,描述文件的文件段里可
写上这么一行:
/etc
如果仅想包含此目录,则可用:
%dir /etc


(3) 另类修饰符
此类只有一个%defattr。说它是另类修饰符,是由于它设定的是默认的文件属性,而非特定
的某个文件。它一般放在文件段内容的第一行。
其使用格式为:
%defattr(权限,属主,属组)

其中: 权限,属主和属组都可以使用减号(-)。使用减号的属性将由系统设定。
例如: %defattr(022,zzz,zhsoft) 设定其后的所有文件权限为022,属主为zzz,属组为
zhsoft;又如: %defattr(-,zzz,-) 则是设定其后的所有文件属主为zzz,权限与属组由系
统设置。
可选的功能段
描述文件中,可选功能段的内容都是些脚本程序。(LZE描述文件中多个脚本程序中仅含一
个echo命令)
可选的功能段的描述格式为:
功能段名 [子包选项]

注: 子包选项为"[-n] 子包名"。当无子包选项时,段内容描述的是父包的脚本程序。当有
子包选项时,段内容则是描述子包的脚本程序。

可选的功能段可分为如下三类:
1. 建包用功能段:
RPM通过源程序来建立一个软件包时,要执行预处理,编译,安装和清理四项操作,分别对应
于%prep,%build,%install和%clean四个段。
下面按其执行顺序逐段进行说明:
1.1 %prep :
此为预处理段,其内容为预处理脚本程序。该程序完成以下任务:
* 建立软件编译用目录;
* 将源程序解压缩;
* 通过打补丁,升级源程序;
* 执行其它一些操作,使源程序随时可进行编译。
在此脚本程序中,可使用如下两个宏命令:
1.1.1 %setup
这个宏利用系统中的gzip与tar等命令,来解压源程序包。RPM会自动探测源程序包是否压
缩,如果压缩,它会用gzip将其解压缩,否则直接用tar命令展开包中文件。其使用格式为:
%setup [-n name] [-c] [-D] [-T] [-b N] [-a N]

注: []所括为可选项。
(1) 当没有任何选项时:
这个宏用来解压默认的源程序包(由文件头Source或Source0域指定)。注意:源程序包中的
文件应用"软件名-版本号"作为其上层目录,这样%setup宏就可以正常工作。如果不以"软
件名-版本号"作为其上层目录,则%setup宏工作时有一个指令"cd 软件名-版本号"(转目录
)会因为系统中没有此目录而出错退出(除非在此宏上面加上建立此目录的命令)。如LZE软
件源程序所在的目录为lze-6.0,我需要用命令"tar cvzf lze-6.0-2.src.tgz lze-6.0"将
源程序打包并压缩,这样的包就可以被%setup宏正确使用了。
下面是%setup宏命令所执行的一系列命令: (指令前面为行号)
1 cd /usr/src/dist/BUILD
2 echo "预处理脚本程序(prep)开始执行"
3 cd /usr/src/dist/BUILD
4 rm -rf lze-6.0
5 /bin/gzip -dc /usr/src/dist/SOURCES/lze-6.0-2.src.tgz | tar -xvvf -
6 STATUS=$?
7 if [ $STATUS -ne 0 ]; then
8exit $STATUS
9 fi
10 cd lze-6.0
11 [ `/usr/bin/id -u` = '0' ] && /bin/chown -Rhf root .
12 [ `/usr/bin/id -u` = '0' ] && /bin/chgrp -Rhf root .
13 /bin/chmod -Rf a+rX,g-w,o-w .
14 exit 1

看,第10行就有一个转到lze-6.0目录的命令,如果没有这个目录,程序就会出错退出了。也
许你要问:这些指令你是怎么知道的?其实这很简单,只要在%setup宏下面加上一句"exit
1"命令,让预处理脚本程序非正常退出即可。这样RPM所执行的预处理脚本程序作为临时文
件在其退出时并未删除,只要看一下这个文件(在/var/tmp目录下以rpm-tmp开头)就知道
%setup宏命令做什么了。

(2) -n name :
上面已经谈到,源程序包中的文件应采用"软件名-版本号"作为上层目录。如果用了别的什
么目录(如name),%setup宏无法正常工作,那该怎么办?没关系,可以用-n选项,引用一下这
个目录(name)就行了。假如我的LZE源程序包中的文件是以lze为上层目录,那么我就可以
用"%setup -n lze"宏命令来解压缩该包。

(3) -c :
此选项的作用是创建上层目录("软件名-版本号"目录)并转到这个目录。对于LZE软件,其
效果相当于在上例的第4行与第5行之间加上这么两行命令:
mkdir -p lze-6.0
cd lze-6.0
它适用的情况是:有的源程序包是在源程序所在目录下打的包,所以其中的文件都没有上层
目录。这样的话,要想正确解压,必须创建上层目录。

(4) -D :
本选项的作用是在解压源程序包之前不要删除软件的上层目录(软件名-版本号)。在上例
中,其效果是不执行第4行的命令(rm -rf lze-6.0)。

(5) -T :
本选项的作用是不解压默认的源程序包(由文件头的Source或Source0域所定义)。在上例
中,其效果是不执行第5-9行的命令:第5行是解压源程序包(用gzip -dc将包的内容解压缩
到管道中,再由tar -xvvf -从管道中读取数据并展开),第6-9行是检查解压命令的返回值
,非0时执行非正常退出。

(6) -b N :
本选项指示RPM在转到上层目录前解压第N个源程序包(由文件头SourceN域定义)。这适用
于含上层目录的源程序包。注意:如果使用此选项时不同时使用-T选项,则RPM解压的是两
个源程序包,一个是默认的包(由Source或Source0域定义),一个是-b选项指定的包(由
SourceN域定义)。这样,当N等于0时,默认的源程序包将被解压两次。所以,如果想仅解压
指定源程序包,请同时使用-T选项,以禁止解压默认的源程序包。
下面的宏命令仅解压第1个源程序包,然后转到上层目录:
%setup -b 1 -T

(7) -a N :本选项指示RPM在转到上层目录后再解压第N个源程序包(由文件头SourceN域定
义)。这适用于不含上层目录的源程序包。使用本选项时,一般加上-c选项,以创建上层目
录并转到此目录。注意:如果使用此选项时不同时使用-T选项,则RPM解压的是两个源程序
包,一个是默认的包(由Source或Source0域定义),一个是-a选项指定的包(由SourceN域定
义)。这样,当N等于0时,默认的源程序包将被解压两次。所以,如果想仅解压指定源程序包
,请同时使用-T选项,以禁止解压默认的源程序包。

下面的宏命令让RPM先转到上层目录,再仅解压第2个源程序包:
%setup -T -a 2
1.1.2 %patch
此宏利用系统中的patch命令,来给指定的源程序包打补丁,从而将程序升级。其使用格式
为:
%patch [-P N] [-p N] [-b name] [-E]
注: []所括为可选项。
为了说明下列选项的作用,我们为LZE软件包描述文件中定义三个补丁文件:
Patch0 : lze-patch.zero
Patch1 : lze-patch.one
Patch2 : lze-patch.three

(1) 当没有任何选项时:
没有任何选项时,该宏使用的是默认的补丁文件(第0个补丁文件),即由文件头Patch或
Patch0域所定义的文件(LZE包使用lze-patch.zero)。
该宏在执行时,扩展为以下指令:
echo "Patch #0:"
patch -p0 -s < /usr/src/dist/SOURCES/lze-patch.zero
注: 第一行指令是利用echo命令向屏幕输出字符串“Patch #0:”。第二行指令则是利用
patch命令读取补丁文件lze-patch.zero升级源程序。
patch命令用了两个选项:(有关patch命令用法,详见其用户手册)
* -p : 这个选项用于确定patch所要操作的文件。它针对补丁文件头部的文件名,删除名
字中指定数目个斜杠(/)前面的所有字符,从而得到要操作的文件名。如补丁文件里有个文
件名/usr/zzz/src/lze.c,则用-p0时patch操作的文件名不变,用-p1时则变为
usr/zzz/src/lze.c,用-p2时则变为zzz/src/lze.c,如用-p4则操作的文件名变为lze.c。
* -s : 这个选项指示patch在打补丁过程中不输出任何信息,即使有错误发生。

(2) -P N :
使用此选项以指示RPM使用第N个补丁文件(由文件头PatchN域定义)。如想让RPM使用LZE的
第2个补丁文件Patch2(lze-patch.three)时,可使用"-P 2"来指定。

(3) -p N :
此选项与其参数是由%patch宏直接传给patch命令的。请参见上面patch命令所用的-p选项
的介绍。

(4) -b name :
当有多个patch命令操作同一个文件时,patch会将原文件换名保存(其后缀变作.orig),如
lze.c会变作lze.orig。如果想用别的名字作后缀,则可用-b设置一下,这样原文件会换名
为"原文件名+后缀",如用-b ZZZ时,lze.c会换名保存为lze.cZZZ。
此选项在执行时,实际上是给patch命令传递了一个选项及参数,即--suffix name。

(5) -E :
此选项直接传给patch命令,其作用是:如果一个文件打完补丁后内容为空(字节数为0),则
删除这个文件。

1.2 %build :
此为编译段,其内容为编译脚本程序。该程序完成源程序的编译和连接。一个最简单的例
子就是程序中仅有一个make命令。这适用于大部分情况,因为多数软件均有自己的
makefile,这样通过make命令就可实现编译与连接。如果没有makefile的话,需要软件包制
作者自己在编译段书写上一系列的编译连接命令。

1.3 %install :
此为安装段,其内容是安装脚本程序。该程序将已编译连接好的执行程序或其它文件存放
到指定目录下,这些程序或文件供RPM打包时使用。一个最简单的例子就是程序中仅用一个
make install命令,从而完成安装。这也需要相应的软件有makefile维护文件。没有的话
,软件包制作者也得自己写指令。

1.4 %clean :
此为清理段,其内容是清理脚本程序。此程序在RPM制作好软件包后才执行,它通常是删除
那些编译连接时产生的临时文件或目录,完成缮后工作。

2. 管理用功能段:
此类段用于软件包自身的管理(安装,卸载和校验),包括%pre,%post,%preun,%postun,和
%verifyscript五个功能段。
2.1 %pre :

该段内容为安装前脚本程序。它在软件包安装之前执行,通常是检测操作环境,建立有关目
录,清理多余文件等等,为软件包的顺利安装做准备。本段很少使用。
其段名格式为: %pre [子包选项]

2.2 %post :
该段内容为安装后脚本程序。它在软件包安装完成之后执行,常用来建立符号连接,修改系
统配置文件,运行ldconfig程序等,以利软件的正常运行。
其段名格式为: %post [子包选项]

2.3 %preun :
该段内容为卸载前脚本程序。它在软件包卸载之前执行,主要为卸载做准备。具体如,要卸
载的软件包中某个程序当前正在运行时,此脚本程序必须杀掉它,否则无法正确卸载。
其段名格式为: %preun [子包选项]

2.4 %postun :
该段内容为卸载后脚本程序。它在软件包卸载后执行,完成卸载的缮后工作,如将系统配置
文件inetd.conf改回原来的样子,重新运行一下ldconfig命令,将已卸载的共享库从缓冲文
件ld.so.cache中删除等等。
其段名格式为: %postun [子包选项]

2.5 %verifyscript :
该段内容为校验脚本程序。RPM校验软件包时,除了执行标准的校验外,如果软件包制作者
设定有此校验脚本程序,还将执行之。

其段名格式为: %verifyscript [子包选项]
下面是XFree86-libs-3.3.6-6.i386.rpm软件包中的校验脚本程序,它校验的是动态链接库
目录/usr/X11R6/lib。校验时,在/etc/ld.so.cache文件中查找/usr/X11R6/lib,如果找不
到,则显示"missing",找到则显示"found"。
# verifyscript
echo -n "Looking for /usr/X11R6/lib in /etc/ld.so.conf... "
if ! grep "^/usr/X11R6/lib$" /etc/ld.so.conf > /dev/null
then
echo "missing"
echo "/usr/X11R6/lib missing from /etc/ld.so.conf" >&2
else
echo "found"
fi

3. 交互用功能段:
这类功能段有%triggerin,%triggerun,%triggerpostun,它们的内容都是RPM用于软件包之
间交互控制的脚本程序。这些脚本程序都是在系统满足指定的条件下才触发执行的:

1) %triggerin : 段内为安装时触发脚本程序,当其所在软件包与指定软件包仅有一方已
安装时,安装另一方将触发此程序执行;

2) %triggerun : 段内为卸载时触发脚本程序,当其所在软件包与指定软件包都已安装时
,卸载二者中的任一个将触发此程序执行;

3) %triggerpostun : 段内为卸载后触发脚本程序,只有指定软件包卸载后才触发此程序
执行。

3.1 段名格式
它们的段名描述格式均为:
交互段名 [子包选项] [-p 解释程序] -- 触发条件1 [,触发条件2] ...

注: []所括为可选项。子包选项见前面介绍,不赘述。

3.1.1 -p选项:
此选项用于指定一个解释程序,来解释执行交互功能段的脚本程序。默认情况下,RPM使
用/bin/sh来执行脚本(此类脚本用SHELL语言编写,也叫SHELL程序)。有的RPM包则是使用
/usr/bin/perl
来执行脚本(此类脚本是用PERL这种解释性语言写的),这就需要用-p选项来指定解释程序

/usr/bin/perl,如:
%triggerin -- sendmail
ln -sf /usr/bin/sendmail /etc/mymailer/mailer
%triggerin -- vmail
ln -sf /usr/bin/vmail /etc/mymailer/mailer

注: 此例中定义package子软件包安装时触发脚本程序:当触发条件
(fileutils>3.0,perl<1.2)满足时,用/usr/bin/perl执行脚本,即用print命令输出字符串
"I'm in my trigger!"。

3.1.2 触发条件:
交互功能段的触发条件格式是:
功能名 [比较符 版本号]

其中:比较符与版本号可选。仅有一个功能名时,表明该功能存在时触发程序执行。比较符
可用大于(>),等于(=),小于(<),大于等于(>=)和小于等于(<=)。
如触发条件bash,又如触发条件fileutils>3.0,这种使用均合法。
交互功能段最少有一个触发条件。当有多个触发条件时,这些条件间均以逗号(,)分隔,它
们之间是"或"的关系,即只要其中有一个条件系统满足,RPM就将执行触发脚本程序。如上
面介绍-p选项时举的例子:例子中有两个触发条件fileutils>3.0和perl<1.2,在安装软件
包时,只要有一个条件满足,RPM就会执行触发脚本,即输出"I'm in my trigger!"。

3.2 交互用功能段的使用
为什么要使用交互用功能段?下面的例子很能说明问题。
假定mymailer软件包需要/etc/mymailer/mailer这个符号连接文件指向当前使用的邮件发
送代理程序。如果sendmail包安装了,那么这个符号连接文件应指向/usr/bin/sendmail程
序。如果vmail包安装了,那么它应当指向/usr/bin/vmail程序。如果这两个软件包都安装
了(实际上,sendmail与vmail彼此是冲突的),那么我们也无需考虑符号连接指向哪个文件
了。当然,如果这两个包都未安装,那么/etc/mymailer/mailer符号连接文件也没有理由存
在了。

上述要求,我们通过为mymailer软件包编写触发脚本程序来实现,这些脚本程序在下列事件
发生时,将改变/etc/mymailer/mailer符号连接的内容:
1) sendmail已安装;
2) vmail已安装;
3) sendmail卸载时;
4) vmail卸载时。

前两个事件触发的脚本程序可以这样写:
%triggerin -- sendmail
ln -sf /usr/bin/sendmail /etc/mymailer/mailer
%triggerin -- vmail
ln -sf /usr/bin/vmail /etc/mymailer/mailer

这是两个安装时被sendmail或vmail所触发脚本程序。它们将在下列情况下执行:
1) 在mymailer包已安装的情况下,安装或升级sendmail包;
2) 在mymailer包已安装的情况下,安装或升级vmail包;
3) 在sendmail包已安装的情况下,安装或升级mymailer包;
4) 在vmail包已安装的情况下,安装或升级mymailer包。
后两个事件触发的脚本程序可以这么写:
%triggerun -- sendmail
[ $2 = 0 ] || exit 0
if [ -f /usr/bin/vmail ]
then
ln -sf /usr/bin/vmail /etc/mymailer/mailer
else
rm -f /etc/mymailer/mailer
fi
%triggerun -- vmail
[ $2 = 0 ] || exit 0
if [ -f /usr/bin/sendmail ]
then
ln -sf /usr/bin/sendmail /etc/mymailer/mailer
else
rm -f /etc/mymailer/mailer
fi

这两个脚本程序在下列情况下触发执行:
1) 在sendmail包已安装的情况下,卸载mymailer包;
2) 在vmail包已安装的情况下,卸载mymailer包;
3) 在mymailer包已安装的情况下,卸载sendmail包;
4) 在mymailer包已安装的情况下,卸载vmail包。
为了确保在mymailer包卸载后符号连接文件/etc/mymailer/mailer也被删除,可以在
mymailer软件包描述文件的%postun功能段内,加上删除该文件的命令:
%postun
[ $1 = 0 ] && rm -f /etc/mymailer/mailer

注: %postun段内为卸载后执行脚本程序,在mymailer包卸载后执行。
由上看出,当一个软件包与另一个软件包存在密切关系时,我们可以通过交互用功能段实现
某些文件的管理,这不仅扩展了RPM软件包管理的功能,又有助于软件包的正常运行。

4. 其它功能段
其它功能段只有一个,即%changelog。这个段的内容是软件维护记录,它记录每次软件维护
的时间,维护人及其EMAIL,维护的项目等。
%changelog段内容格式为:
* 星期 月份 日子 年份 维护内容
注: 每个维护记录均以*开头,星期,月份均须为英文缩写。维护内容多时可分行编写,
每行开头最好以减号(-)开头。可以采用类似LZE方式的维护记录写作格式:(见LZE描述文
件第80-85行)
摘自赛迪网

一个RPM的软件包描述文件,可以仅生成一个父包或一个子包,也可以生成一个父包和多个
子包。通过设定子包选项,可以使生成的子包采用"软件名-子包名"的标准命名,也可使生
成的子包采用自己的名字。一个子包,通常是按照其包含的文件的用途或类型来归并文件
进而打成包裹的。象前面的LZE描述文件很简单,它将所有文件都包含进了父包中。我们也
可以将文件分类作成子软件包,如可分成执行程序子包(lze-bin),配置文件子包
(lze-config)和说明文档包(lze-doc)。我们还可以只分出一个配置文件子包
(lze-config),其余文件均打入父包中(lze)。通过这样详细地分类,有助于用户管理软件
包,避免安装多余的东西,同时也有助于升级。

要想创建子软件包,必须描述以下内容:

1. %package :
用此段创建一个子包。其名字由子包选项控制。子包选项为"[-n] 子包名",不选-n时,生
成的子包文件为"软件名-子包名-版本号-释出号.体系.rpm";选-n时,生成的子包文件为"
子包名-版本号-释出号.体系.rpm"。其应用格式为:

%package 子包选项

2. Summary

此域必须在%package下面,它定义子包功能简介(一句话说明)。格式为:

Summary : 子包简介

3. Group

此域必须在%package下面,其定义子包所属软件类别(软件类别请参见<<精通RPM之五--查
询篇>>)。格式为:

Group : 软件类别

4. %description :

此描述段的内容是较为详细的子包功能介绍,介绍为文本形式,格式不作要求,可任意换行
或分段。格式为:
%description 子包选项
...介绍子包功能的内容...

5. %files :
此文件段的内容是子包所要包含的文件列表。文件列表中,一个文件占用一行,还可使用多
种文件修饰符。(详见<<精通RPM之七--制作篇(上)>>)

段名应用格式为:

%files 子包选项 [-f 文件名]

注意: 上述%description与%files段所用的子包选项形式,必须与%package所用的子包选
项形式一致,否则的话,它们定义的不是同一个子包,RPM检查时将报错退出。如定义过
%package name后,描述段名须用%description name,文件段名须用%files name方可。而
用%description -n name则不行,%files -n name也不行。

子软件包也可使用%pre,%post,%preun,%postun,%triggerin,%triggerun和
%triggerpostun等七个可选的功能段,因为它们都可使用子包选项。当使用子包选项时,它
们的段内容就是用来管理子软件包的脚本程序。要注意的是,这些段使用的子包选项形式
也必须与%package段使用的子包选项形式一致。

条件语句的使用

在软件包描述文件中,可以灵活地使用条件语句,位置不限制。这些语句,用于当前体系与
操作系统的判断,当条件为真或为假时,RPM均会引用其相应的描述内容。

条件语句有两种格式:

1. {%ifarch,%ifnarch,%ifos,%ifnos} 值1 [值2] ...
描述内容
%endif

注: {}所括内容必选其中之一,[]所括为可选项,各个值之间以空格分隔,%endif表示条件
语句结束。

此语句的含义是:
1) 使用%ifarch时,表示如果当前体系为值1或值2...,则引用描述内容。
2) 使用%ifnarch时,表示如果当前体系不为值1或值2...,则引用描述内容。
3) 使用%ifos时,表示如果当前操作系统为值1或值2...,则引用描述内容。
4) 使用%ifnos时,表示如果当前操作系统不为值1或值2...,则引用描述内容。

如果想在LZE包描述文件的文件段增加只适用于sparc体系的文件/etc/sparc.lze和
/etc/sparc.ime,则可在文件段内加入如下语句:
%ifarch sparc
/etc/sparc.lze
/etc/sparc.ime
%endif

这样做以后,如果当前体系为sparc,则RPM在打包时会加入这两个文件。

2. {%ifarch,%ifnarch,%ifos,%ifnos} 值1 [值2] ...
描述内容1
%else
描述内容2
%endif

注: {}所括内容必选其中之一,[]所括为可选项,各个值之间以空格分隔,%else表示另外一
种情况,%endif表示条件语句结束。

此语句的含义是:
1) 使用%ifarch时,表示如果当前体系为值1或值2...,则引用描述内容1,否则引用描述 内
容2。
2) 使用%ifnarch时,表示如果当前体系不为值1或值2...,则引用描述内容1,否则引用描述
内容2。
3) 使用%ifos时,表示如果当前操作系统为值1或值2...,则引用描述内容1,否则引用描述
内容2。
4) 使用%ifnos时,表示如果当前操作系统不为值1或值2...,则引用描述内容1,否则引用描
述内容2。

如果想根据当前操作系统来确定LZE包的名字,则可在描述文件头使用如下语句定义Name域
:
%ifos linux
Name : lzeforlinux
%else

%ifos aix
Name : lzeforaix
%else
Name : lzeforothersys
%endif

%endif

本例中使用了嵌套的条件语句,它说明的情况是:如果操作系统为linux,则软件名定为
lzeforlinux,如果操作系统为aix,则软件名定为lzeforaix,如果不是上述两个操作系统,
则将软件名定为lzeforothersys。

如何在描述文件中使用宏(macros)

1. 宏是什么?
学过C语言的人都知道,宏是用来实现文本替换的,即定义了宏名与宏体后,文件中所有有宏
名的地方在预处理时将被宏体替换掉。使用宏可以减少文字的录入量,方便了编程人员。
在软件包描述文件中使用宏,也是基于这个目的,只不过这个宏与C语言的宏定义格式不同
而已。

2. 宏的定义

描述文件中宏的定义格式为:

%define [(opts)]

注: []所括为可选项。为宏名,宏名可用字母,数字和下划线(_),并且其长度最小为3。
opts为一个或多个选项,各选项之间无分隔,选项采用getopt函数要求的形式,即选项为单
个字符,如果某个选项需要参数,则需要在这个选项后加个冒号(:)。为宏体,它周围的空字
符将被删掉。宏体的内容须在一行上。

如没有选项的宏定义:

%define aaa "This is my software"


如仅有一个选项的宏定义:

%define xxx(p:Z) echo %{-p:%{-p*}} %{-Z}

3. 宏的使用

宏的使用格式为:
% [opt1] [opt2]... [arg1] [arg2]...


%{} [opt1] [opt2]... [arg1] [arg2]...


注: []所括为可选项;为所应用的宏名,宏名可以用{}括住;opt1,opt2...为选项,均须以减
号(-)开头,并且如果选项需要参数,则必须提供一个选项参数;arg1,arg2...则为宏的参数


如上面定义的xxx宏,可这样使用:

%xxx -p zhsoft hello world<
br>
例子中,xxx宏使用一个选项-p,zhsoft为-p选项的参数,还有两个宏的参数hello和world。


注意: 宏使用时最好多换一行(即宏下面空一行),因为宏在扩展后并不换行,这样如果不多
换行,则下面一行若有内容的话,宏扩展后的内容将和下面一行的内容合并在一起,极容易
出现错误。这也是笔者发现RPM宏的问题之一。还有一个问题,如果注释行上存在宏,则这
个宏也将扩展,错矣!因为注释本来就是要忽略掉的,有宏也不必再扩展了。这两个问题都
需要引起RPM开发者的注意,并切实加以解决。

4. 宏体专用的宏
宏体中可使用如下专用的宏:(类似SHELL形式的宏)

1) %0 : 表示所在宏的宏名;
2) %* : 表示宏的所有参数;
3) %# : 表示宏的参数个数;
4) %{-f} : 表示如果宏使用了-f选项,则它表示-f及其选项参数;
5) %{-f*} : 表示如果宏使用了-f选项,则它表示-f所带的参数;
6) %{-f:X} : 表示如果宏使用了-f选项,则它表示X;
7) %{!-f:Y} : 表示如果宏没有使用-f选项,则它表示Y;
8) %1,%2,... : 表示宏的参数1,参数2...

如,上例中xxx宏执行时,若宏体中有上述专用的宏,则专用宏将会扩展为:

1) %0扩展为xxx;
2) %*扩展为hello world;
3) %#扩展为2;
4) %{-p}扩展为-p zhsoft;
5) %{-p*}扩展为zhsoft;
6) %{-p:good}扩展为good;
7) %{!-Z:bad}扩展为bad; (因为xxx宏未使用-Z选项)
8) %1为hello,%2为world,没有其它参数。

5. 系统内置的宏

系统内置的宏可分如下三类:

5.1 定义类
1) %define ... : 定义一个宏;(原来,%define也是一个宏啊)
2) %undefine ... : 取消一个宏;(宏取消后,此语句下面的描述文件就不能再使用这个宏
了,即使使用,该宏也不会被扩展了)

5.2 调试类
1) %trace : 打印宏扩展前后的调试信息;
2) %dump : 打印活动的宏(宏名及宏体);
3) %{echo:...} : 打印...到标准错误设备;
4) %{warn:...} : 打印...到标准错误设备;
5) %{error:...} : 打印...到标准错误设备,并且返回BADSPEC值;

5.3 特殊类
这类宏的默认值通常放在/usr/lib/rpm/macros文件中,用户通过编辑自己主目录(HOME)下
的.rpmmacros文件(~/.rpmmacros),可重定义这类宏,改变其默认值,以供RPM在软件包制作
,安装及查询时使用自己的定义。

这类宏的定义格式为:

%


注: 为宏名,为宏体。

1) %packager,%vendor,%distribution :

这三个宏用于定义描述文件中Packager,Vendor,Distribution三个可选域的默认的域值,
即如果这三个域中有哪个未在描述文件中定义,且其相对应的宏有定义,则RPM会采用其对
应的宏的宏体。

如我的~/.rpmmacros文件中有这样三行:

%vendor 纵横软件制作中心
%packager 雨亦奇
%distribution 小赵'2001

这样,软件包描述文件中再也不用定义那三个域了,由此制作出来的软件包在查询时,其打
包者(Packager),销售商(Vendor)及发行版(Distribution)均自动搞定了,一劳永逸。

2) %buildroot,%_provides :

这两个宏定义软件包建包时用的根目录及软件包所提供的功能。它们在打包时不会象 上
面那三个宏一样主动被RPM采用,而是必须在描述文件中写那么几行。即:

%vendor 纵横软件制作中心
%packager 雨亦奇
%distribution 小赵'2001
Buildroot : %buildroot
Provides : %_provides

3) %_topdir,%_builddir,%_rpmdir,%_sourcedir,%_specdir,%_srcrpmdir :

这六个宏都是RPM制作软件包时要用的,它们在/usr/lib/rpm/macros文件中的默认值为:

%_topdir %{_usrsrc}/dist
%_builddir %{_topdir}/BUILD
%_rpmdir %{_topdir}/RPMS
%_sourcedir %{_topdir}/SOURCES
%_specdir %{_topdir}/SPECS
%_srcrpmdir %{_topdir}/SRPMS

%_topdir宏定义的是RPM制作软件包时所用目录的顶层目录,一般为
/usr/src/dist(%{_usrsrc} 宏的值为/usr/src)。在顶层目录下面,又有五个子目录:

* 编译连接源程序时用的目录,由%_builddir宏定义,常用BUILD;
* 生成的RPM执行程序包存放的目录,由%_rpmdir宏定义,常用RPMS;
* 软件源程序存放的目录,由%_sourcedir宏定义,常用SOURCES;
* 软件包描述文件存放的目录,由%_specdir宏定义,常用SPECS;
* 生成的RPM源程序包存放的目录,由%_srcrpmdir宏定义,常用SRPMS。

由于宏的递归特性,我们可以通过只定义%_topdir宏来达到改变%_builddir等五个宏的目
的。(注意:%_builddir等五个宏的宏体如无特殊要求,尽量不要改变,它们是标准的定义,
应该采用)这对于普通用户来说,意义非常重大。因为RPM默认的顶层目录/usr/src/dist并
不是每个用户都可以随便使用的,普通用户更想在自己所有的目录下用RPM来制作些软件包
。我也有这种想法,所以在~/.rpmmacros文件里加上这么一行:

%_topdir /usr/zzz/rpm


同时,在此宏定义的目录下面建立了RPM所需的子目录,使用命令为:

$ cd /usr/zzz
$ mkdir -p rpm/{BUILD,RPMS/i386,SOURCES,SPECS,SRPMS}
$

命令中的i386是RPM默认的体系名,RPM生成的执行程序包是存放在“RPMS/体系名”目录下
面的。这么做以后,我就可以在自己的目录下制作RPM软件包了,象超级用户一样自由。

4)%_excludedocs,%_ftpport,%_ftpproxy,%_httpport,%_httpproxy,%_netsharepath :

这六个宏对RPM软件包的安装和查询起作用。

* %_excludedocs : 如果其值定义为1,则RPM安装软件包时,对说明文档的默认作法是不安
装;
* %_ftpport : 此宏用于定义RPM默认的FTP端口;
* %_ftpproxy : 此宏用于定义RPM默认的FTP代理服务器;
* %_httpport : 此宏用于定义RPM默认的HTTP端口;
* %_httpproxy : 此宏用于定义RPM默认的HTTP代理服务器;
* %_netsharepath : 此宏用于定义RPM默认的网络共享目录,适用于网络文件系统(NFS)。


6. 一种特殊的宏
这种宏的用法是:

%(SHELL命令及其参数)

它的结果是取指定的SHELL命令的标准输出的结果作为描述文件内容的一部分。如软件包
描述文件的某个部分需要加上当前日期,则可以用:

%(date +%Y-%m-%d)


执行后,该宏将扩展为类似2001-10-31的日期数据。用户不妨在自己的描述文件的预处理
段(%prep)内加上这么两行试试:

%(date +%Y-%m-%d)
exit 1

注: exit 1用于中止RPM的执行。

描述文件模板
以下所有描述文件模板均以LZE软件包制作为例,以源程序现场编译后产生的文件为准生成
软件包。描述文件中一般只描述必要的部分。另外,如果文件段的所有文件已存在于系统
中,并且想直接利用打包,则可以去掉Source域,去掉RPM建包用功能段
(%prep,%build,%install,%clean)。

1. 只有父包,没有任何子包:
此描述文件见<<精通RPM之七--制作篇(上)>>。此文件中还可以去掉几个可选的功能段,
如%pre,%post,%preun,%postun,%triggerin,%triggerun,%triggerpostun。这几个段在此
文件中无实质用途,执行时仅显示RPM开始执行某个脚本程序的信息。此描述文件仅生成软
件包lze-6.0-2.i386.rpm(父包)。

2. 有父包,也有子包:

描述文件如下:

1 # 文件名称: lze-6.0-2.spec1
2 # 文件功能: lze软件包描述信息
3 # 文件作者: 纵横软件制作中心雨亦奇 国防大学研究生二队赵建利
4 # 修改时间: 2001.10.31
5
6 Name: lze
7 Version: 6.0
8 Release: 2
9 Summary: 小赵全屏幕中英文多窗口多功能编辑器(LINUX/UNIX系统适用)
10 Group: Applications/Editors
11 License: Share
12 Source: http://zhsoft.myetang.com/lze-6.0-2.src.tgz
13
14 %description
15 小赵编辑器,是为使用SCO UNIX,LINUX多用户系统的广大用户专门设计的全屏幕多窗
16 口中英文多功能编辑器。
17 它主要有以下十大特点:1.全屏幕菜单操作。2.显示方式多样。3.块操作丰富。4.十
18 字制表功能强大。5.多窗口操作灵活自如。6.文件操作功能齐全。7.解释输出功能独
具特
19 色。8.自带中文输入法(增强五笔和增强拼音),实用方便。9.十六进制编辑功能,
如虎
20 添翼。10.即时翻译,按到即译。
21 总之,小赵编辑器会成为您在UNIX,LINUX系统上编制程序和书写一般性文稿的好帮手

22 它将在工作中助您一臂之力,轻松上阵,游刃有余!
23
24 %prep
25 echo "预处理脚本程序(prep)开始执行"
26 %setup
27
28 %build
29 echo "编译连接脚本程序(build)开始执行"
30 make
31
32 %install
33 echo "安装脚本程序(install)开始执行"
34 make install
35
36 # 配置文件子包
37 %package config
38 summary : 小赵编辑器LZE的配置文件
39 group : Applications/Editors
40
41 %description config
42 小赵编辑器用配置文件包括功能键定义文件与
43 输入法控制文件,用户可根据实际情况加以修改。
44
45 %files config
46 %config /etc/funkey.def
47 %config /etc/inputme.def
48
49 # 说明文档子包
50 %package doc
51 summary : 小赵编辑器LZE的说明文档
52 group : Applications/Editors
53
54 %description doc
55 小赵编辑器说明文档,详细介绍了该编辑器的
56 命令行用法及内置的各项菜单的功能与操作,对用
57 户熟悉小赵编辑器有很大作用。
58
59 %files doc
60 %doc /usr/doc/lze-6.0/README
61 %doc /usr/doc/lze-6.0/LICENSE
62
63 # 父包文件段
64 %files
65 %defattr (-,root,root)
66 /usr/bin/lze
67 /usr/bin/lzeime.py
68 /usr/bin/lzeime.wb
69 /etc/wbzc.dat
70
此描述文件生成软件包有:lze-6.0-2.i386.rpm(父包),lze-config-6.0-2.i386.rpm(配置
文件子包)和lze-doc-6.0-2.i386.rpm(说明文档子包)。

3. 没有父包,只有子包:
没有父包,意味着描述文件中可以没有父包的文件段(%files),请看下面的描述文件:

1 # 文件名称: lze-6.0-2.spec2
2 # 文件功能: lze软件包描述信息
3 # 文件作者: 纵横软件制作中心雨亦奇 国防大学研究生二队赵建利
4 # 修改时间: 2001.10.31
5
6 Name: lze
7 Version: 6.0
8 Release: 2
9 Summary: 小赵全屏幕中英文多窗口多功能编辑器(LINUX/UNIX系统适用)
10 Group: Applications/Editors
11 License: Share
12 Source: http://zhsoft.myetang.com/lze-6.0-2.src.tgz
13
14 %description
15 小赵编辑器,是为使用SCO UNIX,LINUX多用户系统的广大用户专门设计的全屏幕多窗
16 口中英文多功能编辑器。
17 它主要有以下十大特点:1.全屏幕菜单操作。2.显示方式多样。3.块操作丰富。4.十
18 字制表功能强大。5.多窗口操作灵活自如。6.文件操作功能齐全。7.解释输出功能独
具特
19 色。8.自带中文输入法(增强五笔和增强拼音),实用方便。9.十六进制编辑功能,
如虎
20 添翼。10.即时翻译,按到即译。
21 总之,小赵编辑器会成为您在UNIX,LINUX系统上编制程序和书写一般性文稿的好帮手

22 它将在工作中助您一臂之力,轻松上阵,游刃有余!
23
24 %prep
25 echo "预处理脚本程序(prep)开始执行"
26 %setup
27
28 %build
29 echo "编译连接脚本程序(build)开始执行"
30 make
31
32 %install
33 echo "安装脚本程序(install)开始执行"
34 make install
35
36 # 配置文件子包
37 %package config
38 summary : 小赵编辑器LZE的配置文件
39 group : Applications/Editors
40
41 %description config
42 小赵编辑器用配置文件包括功能键定义文件与
43 输入法控制文件,用户可根据实际情况加以修改。
44
45 %files config
46 %config /etc/funkey.def
47 %config /etc/inputme.def
48
49 # 说明文档子包
50 %package doc
51 summary : 小赵编辑器LZE的说明文档
52 group : Applications/Editors
53
54 %description doc
55 小赵编辑器说明文档,详细介绍了该编辑器的
56 命令行用法及内置的各项菜单的功能与操作,对用
57 户熟悉小赵编辑器有很大作用。
58
59 %files doc
60 %doc /usr/doc/lze-6.0/README
61 %doc /usr/doc/lze-6.0/LICENSE
62
63 # 执行程序子包
64 %package bin
65 summary : 小赵编辑器LZE的执行程序
66 group : Applications/Editors
67
68 %description bin
69 小赵编辑器执行程序为lze,五笔输入法服务器执行程序
70 为lzeime.wb,拼音输入法服务器执行程序为lzeime.py。
71
72 %files bin
73 %defattr (-,root,root)
74 /usr/bin/lze
75 /usr/bin/lzeime.py
76 /usr/bin/lzeime.wb
77 /etc/wbzc.dat
78

此描述文件生成三个软件包:lze-config-6.0-2.i386.rpm(配置文件子包
),lze-doc-6.0-2.i386.rpm(说明文档子包),lze-bin-6.0-2.i386.rpm(执行程序子包)。

(责任编辑 尤北 lvye@staff.ccidnet.com)

要想制作RPM格式的软件包,需使用如下命令格式:

rpm-bX[制作选项1制作选项2...]描述文件1描述文件2...

注:-bX可用-tX替换,效果有所不同:使用-b时,需要在命令行上指定软件包描述文件;而使
用-t时,在命令行上需要指定的不是软件包描述文件,而是含有此描述文件的TAR格式的包
裹文件(必须用gzip压缩),RPM在准备制作软件包时,会自动从此包裹文件中提取描述文件
,根据其中的建包指令,生成RPM格式的软件包。注意:此描述文件必须以.spec为后缀,其中
必须有Source域,并且此域定义的源程序包必须存放在当前目录下,否则的话,RPM将报错退
出。
注意,-bX与-tX当中的X,取不同的值时,RPM将执行不同的操作:(下面各个例子均对LZE的描
述文件lze-6.0-2.spec进行操作,有的则通过管道技术,用nl命令给输出加上行号,以便解
释)

1)X=p时,指示RPM执行描述文件中的预处理段(%prep)的脚本程序。该脚本程序一般用来解
压源程序包,并且为源程序打补丁,升级源程序。
#rpm-bplze-6.0-2.spec2>&1|nl
1Executing:%prep
2+umask022
3+cd/usr/src/dist/BUILD
4+echo'预处理脚本程序(prep)开始执行'
5预处理脚本程序(prep)开始执行
6+cd/usr/src/dist/BUILD
7+rm-rflze-6.0
8+/bin/gzip-dc/usr/src/dist/SOURCES/lze-6.0-2.src.tgz
9+tar-xvvf-
10drwxr-xr-xroot/root02001-11-0216:02lze-6.0/
11-rw-------root/root2462262001-11-0216:00lze-6.0/lze.c
12-rw-------root/root982492001-11-0216:00lze-6.0/lzeime.wb.c
13-rw-------root/root3399022001-11-0216:00lze-6.0/lzeime.py.c
14-rw-r--r--root/root12832001-11-0216:00lze-6.0/funkey.def
15-rwxr--r--root/root2502001-11-0216:00lze-6.0/inputme.def
16-rw-r--r--root/root8132742001-11-0216:00lze-6.0/wbzc.dat
17-rw-------root/root4742001-11-0216:02lze-6.0/makefile
18+STATUS=0
19+'['0-ne0']'
20+cdlze-6.0
21++/usr/bin/id-u
22+'['0=0']'
23+/bin/chown-Rhfroot.
24++/usr/bin/id-u
25+'['0=0']'
26+/bin/chgrp-Rhfroot.
27+/bin/chmod-Rfa+rX,g-w,o-w.
28+exit0
#

注:本例中第1行显示的"Executing:%prep"表明RPM开始执行预处理段的脚本程序。例中行
号后那些以加号(+)开始的行均为预处理段脚本程序的指令,其它内容则为指令执行所输出
的结果。从预处理段脚本程序所执行的指令,我们就可以看出RPM正在做什么:
第2行:设置文件创建掩码;
第3行:转到RPM默认的编译目录;
第4行:回显字符串,这才是用户所写的预处理段脚本程序的开始,第2,3行均是RPM增加的指
令;
第6-27行:为%setup所扩展出来的指令及其执行结果,其中可以看到RPM用gzip命令解压
LZE的源程序包(第8行),而后用tar命令展开源程序包(第9行)。
第28行:正常退出,返回值为0。

2)X=l时,指示RPM检查文件段(%files),看其中的文件是否存在。如果不存在,则RPM会报错
退出。
#rpm-bl-vvlze-6.0-2.spec|nl
1Processingfiles:lze
2D:File0:0100644root.root/etc/funkey.def
3D:File1:0100644root.root/etc/inputme.def
4D:File2:0100644root.root/usr/doc/lze-6.0-2/README
5Filenotfound:/usr/doc/lze-6.0-2/LICENSE
6D:File3:0100555root.root/usr/bin/lze
7D:File4:0100511root.root/usr/bin/lzeime.py
8D:File5:0100511root.root/usr/bin/lzeime.wb
9D:File6:0100644root.root/etc/wbzc.dat
10Provides:lze-edit
11PreReq:/bin/sh
12Requires:/bin/sh
#

注:本例命令中使用了通用选项-vv,以输出RPM检查时的调试信息(以行号和D:开始的行)。

由上看出,RPM对文件段的所有文件逐一进行检查,找到的文件显示其权限,属主和属组信息
,结果发现/usr/doc/lze-6.0-2.LICENSE文件不存在,于是报出错误(File not found)(见
第5行)。RPM在检查过文件后,还显示出描述文件要求LZE提供的功能(Provides)和所需的
功能(Requires)。

3)当X=c时,指示RPM依次执行预处理段(%prep),编译段(%build)的脚本程序。编译段的脚
本程序用来编译连接软件的源程序,生成可执行程序,通常一个make命令足够。因为一个有
良好习惯的程序员会把Makefile(程序维护文件)写好,以便其它程序员编译该软件。如果
某个软件没有维护文件的话,用户要么自己写个Makefile,要么在编译段里写上软件编译与
连接的各项命令。

4)当X=i时,指示RPM依次执行预处理段(%prep),编译段(%build)和安装段(%install)的脚
本程序。安装段的脚本程序的任务是将编译连接好的执行程序拷贝到适当的目录(如
/bin,/usr/bin等公共执行目录),以便打包或执行。它通常执行的指令是make install。

5)当X=b时,指示RPM依次执行预处理段(%prep),编译段(%build),安装段(%install)的脚本
程序,之后根据文件段(%files)的文件列表,将文件打包,生成RPM执行程序包,最后执行清
理段(%clean)。
#rpm-bblze-6.0-2.spec2>&1|nl
1Executing:%prep
2+umask022
3+cd/usr/src/dist/BUILD
4+echo'预处理脚本程序(prep)开始执行'
5预处理脚本程序(prep)开始执行
6+cd/usr/src/dist/BUILD
7+rm-rflze-6.0
8+tar-xvvf-
9+/bin/gzip-dc/usr/src/dist/SOURCES/lze-6.0-2.src.tgz
10drwxr-xr-xroot/root02001-11-0217:04lze-6.0/
11-rw-------root/root2462262001-11-0216:00lze-6.0/lze.c
12-rw-------root/root982492001-11-0216:00lze-6.0/lzeime.wb.c
13-rw-------root/root3399022001-11-0216:00lze-6.0/lzeime.py.c
14-rw-r--r--root/root12832001-11-0216:00lze-6.0/funkey.def
15-rwxr--r--root/root2502001-11-0216:00lze-6.0/inputme.def
16-rw-r--r--root/root8132742001-11-0216:00lze-6.0/wbzc.dat
17-rw-------root/root4742001-11-0216:02lze-6.0/makefile
18-rw-r--r--root/root12552001-11-0217:04lze-6.0/getinputme.c
19+STATUS=0
20+'['0-ne0']'
21+cdlze-6.0
22++/usr/bin/id-u
23+'['0=0']'
24+/bin/chown-Rhfroot.
25++/usr/bin/id-u
26+'['0=0']'
27+/bin/chgrp-Rhfroot.
28+/bin/chmod-Rfa+rX,g-w,o-w.
29+exit0
30Executing:%build
31+umask022
32+cd/usr/src/dist/BUILD
33+cdlze-6.0
34+echo'编译连接脚本程序(build)开始执行'
35编译连接脚本程序(build)开始执行
36+make
37cc-fwritable-strings-DUSE_AS_LZE-DFOR_LINUX-s-I/usr/zzz/src/include-DFOR_LZE
_INPUTME-olze/usr/zzz/src/li-
38bsrc/mycurses.clze.cgetinputme.c/usr/zzz/src/my.a
39cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.wbgetinputme.clzeime.wb.c/usr/
zzz/src/my.a
40lzeime.wb.c:Infunction`do_service':
41lzeime.wb.c:1409:warning:passingarg5of`bsearch'fromincompatiblepointertype
42cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.pygetinputme.clzeime.py.c/usr/
zzz/src/my.a
43+exit0
44Executing:%install
45+umask022
46+cd/usr/src/dist/BUILD
47+cdlze-6.0
48+echo'安装脚本程序(install)开始执行'
49安装脚本程序(install)开始执行
50+makeinstall
51installing...
52done
53+exit0
54Processingfiles:lze
55FindingProvides:(using/usr/lib/rpm/find-provides)...
56FindingRequires:(using/usr/lib/rpm/find-requires)...
57Provides:lze-edit
58PreReq:/bin/sh
59Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.
1)
60Wrote:/usr/src/dist/RPMS/i386/lze-6.0-2.i386.rpm
61Executing:%clean
62+umask022
63+cd/usr/src/dist/BUILD
64+cdlze-6.0
65+echo'建包结束后清理脚本程序(clean)开始执行'
66建包结束后清理脚本程序(clean)开始执行
67+exit0
#

注:本例中,各行解释如下:
第1行:显示RPM开始执行预处理段(%prep);
第2-29行:为预处理段(%prep)脚本程序执行的命令与结果,命令前有加号(+),结果前面则
没有。预处理完成了LZE源程序包的解压缩(gzip-dc)与包的展开(tar-xvvf),从而为源程
序的编译打下了基础;
第30行:RPM表示开始执行编译段(%build);
第31-43行:为编译段(%build)脚本程序执行的命令与结果。脚本程序执行的make维护命令
,该命令执行了cc编译程序,以编译与连接LZE软件;
第44行:RPM表示开始执行安装段(%install);
第45-53行:为安装段(%install)脚本程序执行的命令与结果。本段程序执行了
makeinstall命令,将LZE的执行程序等文件拷贝到系统目录下;
第54行:RPM显示:开始处理LZE的文件(为%files文件段的内容);
第55-59行:RPM利用/usr/lib/rpm/find-provides程序查找LZE提供的功能,又利用
/usr/lib/rpm/find-requires查找LZE所依赖的功能,以设定LZE的依赖关系;
第60行:制作完成LZE执行程序包,文件名为lze-6.0-2.i386.rpm,在
/usr/src/dist/RPMS/i386目录下;
第61行:RPM显示:开始执行清理段(%clean)脚本程序,本段程序用于清理临时文件;
第62-67行:为清理段(%clean)脚本程序执行的命令与结果。

从上我们可以清楚看出RPM制作软件包的工作流程:预处理段,编译段,安装段,软件包制作
,清理段。

6)当X=s时,指示RPM建立源码包。RPM源码包的内容包括软件包描述文件(SPEC),软件源程
序,软件补丁程序,图标文件等几项。建立源码包不需要执行软件包描述文件中的各个功能
段,仅需将所需文件包含到包中即可。

#rpm-bslze-6.0-2.spec
Wrote:/usr/src/dist/SRPMS/lze-6.0-2.src.rpm
#rpm-qplv/usr/src/dist/SRPMS/lze-6.0-2.src.rpm
-rw-------rootroot206711月215:44lze-6.0-2.spec
-rw-r--r--rootroot53870611月217:05lze-6.0-2.src.tgz
#

注:本例中,使用rpm-bs命令生成了LZE源码包lze-6.0-2.src.rpm(在RPM标准源码目录
/usr/src/dist/SRPMS下),然后用rpm -qplv命令查询源码包中所含的文件信息,从中可以
看到LZE源码包中有两个文件:一个是软件包描述文件lze-6.0-2.spec,一个是LZE源代码包
lze-6.0-2.src.tgz(TAR打包再用gzip压缩),此文件由描述文件中的Source域确定。

7)当X=a时,指示RPM依次执行预处理段(%prep),编译段(%build),安装段(%install)脚本程
序,之后先生成RPM源码包,再根据文件段(%files)的文件列表,将文件打包,生成RPM执行程
序包,最后执行清理段(%clean)脚本程序,清除中间文件。此命令执行的结果相当于先执行
rpm-bs命令生成源码包,再执行rpm-bb命令生成执行码包。

选项列表


选项详解

通用选项的解释见<<精通RPM之二--安装篇>>,本文不再赘述。

1.--short-circuit:单步执行
此选项的目的在于单步执行功能段,仅适用命令为RPM-bc(或-tc)和-bi(或-ti)时。当用
rpm-bc--short-circuit命令时,RPM将不再执行预处理段(%prep)的脚本程序,直接执行编
译段(%build)的脚本程序。当用rpm-bi--short-circuit命令时,RPM将不再执行预处理段
(%prep)和编译段(%build)的脚本程序,仅执行安装段(%install)的脚本程序。

为什么要使用这个选项?其原因可能是源程序包中的文件有问题,导致RPM在编译或安装过
程中出现了这样或那样的错误,如不能单步执行,则无法排除这些错误。单步执行后,用户
可以进入源程序所在的目录,查看源程序,修改错误,然后再用tar命令生成一个正确的源程
序包,覆盖掉原包即可。这样,RPM再制作时就不会有问题了。

2.--timecheck:设置时间检查值
该选项的用法是:--timecheck<secs>
注:<secs>为检查的时间段,单位是秒,如--timecheck600设置检查的时间段为600秒,即10
分钟。

设置时间检查值的目的,在于检验打包文件是否是指定时间段内产生的新文件,如果不是,
则RPM会产生警告信息,提醒用户某个文件不是新文件,而是老文件,可能是某种错误导致的
。这种错误,可能是由于makefile(维护文件)或描述文件中的安装段脚本程序书写不正确
,从而使某个程序不能正确安装到指定目录,因而RPM打包时总是引用老的程序文件。如下
面的例子:
#rpm-bl--timecheck600lze-6.0-2.spec
Processingfiles:lze
warning:TIMECHECKfailure:/usr/bin/lze
FindingProvides:(using/usr/lib/rpm/find-provides)...
FindingRequires:(using/usr/lib/rpm/find-requires)...
Provides:lze-edit
PreReq:/bin/sh
Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)

#

注:本例中利用RPM检查文件列表,看哪个文件是在10分钟以前产生的老文件,结果RPM发出
警告信息:“warning:TIMECHECKfailure:/usr/bin/lze”,这说明文件/usr/bin/lze时间
检查出现错误,这是个老文件。经查,是makefile的问题,里面少了一句“cplze/usr/bin”
。修正后,再次编译连接程序,再进行时间检查就没有这个问题了。

3.--buildroot:设定建包用根目录
该选项的用法是:
--buildroot<dir>

注:<dir>为用户指定的建包用的根目录。
此选项相当于在软件包描述文件的文件头加上一行:
Buildroot:<dir>

只不过在命令行上设定比较自由罢了。

通过设定建包用根目录,一般用户也可以建立那些只有超级用户(root)才能建立的RPM包了
。下面以普通用户zzz建立LZE软件包为例,说明一下这种形式的包的建立过程。

1)在用户zzz的HOME目录(/usr/zzz)下,建立RPM建包所用的目录:
$cd/usr/zzz
$mkdir-prpm/{BUILD,RPMS/i386,SOURCES,SPECS,SRPMS}
$

2)拷贝描述文件lze-6.0-2.spec到rpm/SPECS目录,拷贝源程序包lze-6.0-2.src.tgz到
rpm/SOURCES目录。

$cd/usr/zzz
$cp/root/lze-6.0-2.specrpm/SPECS
$cp/root/lze-6.0-2.src.tgzrpm/SOURCES
$

3)建立.rpmmacros文件,编辑它:
$cd/usr/zzz
$vi.rpmmacros
在此文件中增加一行:
%_topdir/usr/zzz/rpm

用于确定RPM建包用的顶层目录为/usr/zzz/rpm。

4)转到描述文件目录,编辑修改lze-6.0-2.spec安装段的脚本程序:
$cd/usr/zzz/rpm/SPECS
$vilze-6.0-2.spec
$

用于确定RPM建包用的顶层目录为/usr/zzz/rpm。

安装段脚本程序修改为:(原make命令被注释掉)

%install
echo"安装脚本程序(install)开始执行"
#makeinstall
mkdir-p$RPM_BUILD_ROOT/usr/bin
mkdir-p$RPM_BUILD_ROOT/etc
mkdir-p$RPM_BUILD_ROOT/usr/doc/lze-6.0
cplzelzeime.wblzeime.py$RPM_BUILD_ROOT/usr/bin
cpinputme.deffunkey.defwbzc.dat$RPM_BUILD_ROOT/etc
cp/usr/doc/lze-6.0/*$RPM_BUILD_ROOT/usr/doc/lze-6.0


注:脚本程序中,使用建包用根目录的环境变量RPM_BUILD_ROOT,相继在建包用根目录下创
建若干子目录(usr/bin,etc,usr/doc/lze-6.0),然后拷贝程序或文件到相应的子目录中,
从而完成完装。 5)选用--buildroot选项,执行RPM建包命令:
$cd/usr/zzz/rpm/SPECS
$rpm-bb--buildroot/usr/zzz/tmplze-6.0-2.spec
Executing:%prep
+umask022
+cd/usr/zzz/rpm/BUILD
+echo'预处理脚本程序(prep)开始执行'
预处理脚本程序(prep)开始执行
+cd/usr/zzz/rpm/BUILD
+rm-rflze-6.0
+/bin/gzip-dc/usr/zzz/rpm/SOURCES/lze-6.0-2.src.tgz
+tar-xvvf-
drwxr-xr-xroot/root02001-11-0217:04lze-6.0/
-rw-------root/root2462262001-11-0216:00lze-6.0/lze.c
-rw-------root/root982492001-11-0216:00lze-6.0/lzeime.wb.c
-rw-------root/root3399022001-11-0216:00lze-6.0/lzeime.py.c
-rw-r--r--root/root12832001-11-0216:00lze-6.0/funkey.def
-rwxr--r--root/root2502001-11-0216:00lze-6.0/inputme.def
-rw-r--r--root/root8132742001-11-0216:00lze-6.0/wbzc.dat
-rw-------root/root4742001-11-0216:02lze-6.0/makefile
-rw-r--r--root/root12552001-11-0217:04lze-6.0/getinputme.c
+STATUS=0
+'['0-ne0']'
+cdlze-6.0
++/usr/bin/id-u
+'['500=0']'
++/usr/bin/id-u
+'['500=0']'
+/bin/chmod-Rfa+rX,g-w,o-w.
+exit0
Executing:%build
+umask022
+cd/usr/zzz/rpm/BUILD
+cdlze-6.0
+echo'编译连接脚本程序(build)开始执行'
编译连接脚本程序(build)开始执行
+make
cc-fwritable-strings-DUSE_AS_LZE-DFOR_LINUX-s-I/usr/zzz/src/include-DFOR_LZE_I
NPUTME-olze/usr/zzz/src/libsrc/mycurses.clze.cgetinputme.c/usr/zzz/src/my.a
cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.wbgetinputme.clzeime.wb.c/usr/zz
z/src/my.a
lzeime.wb.c:Infunction`do_service':
lzeime.wb.c:1409:warning:passingarg5of`bsearch'fromincompatiblepointertype
cc-DFOR_LINUX-s-I/usr/zzz/src/include-olzeime.pygetinputme.clzeime.py.c/usr/zz
z/src/my.a
+exit0
Executing:%install
+umask022
+cd/usr/zzz/rpm/BUILD
+cdlze-6.0
+echo'安装脚本程序(install)开始执行'
安装脚本程序(install)开始执行
+mkdir-p/usr/zzz/tmp/usr/bin
+mkdir-p/usr/zzz/tmp/etc
+mkdir-p/usr/zzz/tmp/usr/doc/lze-6.0
+cplzelzeime.wblzeime.py/usr/zzz/tmp/usr/bin
+cpinputme.deffunkey.defwbzc.dat/usr/zzz/tmp/etc
+cp/usr/doc/lze-6.0/LICENSE/usr/doc/lze-6.0/README/usr/zzz/tmp/usr/doc/lze-6.0

+exit0
Processingfiles:lze
FindingProvides:(using/usr/lib/rpm/find-provides)...
FindingRequires:(using/usr/lib/rpm/find-requires)...
Provides:lze-edit
PreReq:/bin/sh
Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)

Wrote:/usr/zzz/rpm/RPMS/i386/lze-6.0-2.i386.rpm
Executing:%clean
+umask022
+cd/usr/zzz/rpm/BUILD
+cdlze-6.0
+echo'建包结束后清理脚本程序(clean)开始执行'
建包结束后清理脚本程序(clean)开始执行
+exit0
$
注:RPM建包成功后,生成了/usr/zzz/rpm/RPMS/i386/lze-6.0-2.i386.rpm包裹文件,
通过RPM的查询命令,我们就可以知道该包与由超级用户建成的包内容毫无二致:
$rpm-qplv/usr/zzz/rpm/RPMS/i386/lze-6.0-2.i386.rpm
-rw-r--r--rootroot128311月609:24/etc/funkey.def
-rwxr-xr-xrootroot25011月609:24/etc/inputme.def
-rw-r--r--rootroot81327411月609:24/etc/wbzc.dat
-rwxr-xr-xrootroot40863211月609:24/usr/bin/lze
-rwxr-xr-xrootroot8292011月609:24/usr/bin/lzeime.py
-rwxr-xr-xrootroot3856811月609:24/usr/bin/lzeime.wb
-rw-r--r--rootroot121511月609:24/usr/doc/lze-6.0/LICENSE
-rw-r--r--rootroot369011月609:24/usr/doc/lze-6.0/README
$

现在我们可以说,普通用户也可以自由地建立各种形式的RPM软件包了!

4.--target:设定目标平台
该选项的用法为:--target体系-平台-操作系统
注:RPM制作出来的软件包默认的体系为i386,平台为pc,操作系统为linux。如果用户想加
以改变,就需要使用此选项来确定一下,如下例:
#rpm-bb--targeti686-pc-solaris--quietlze-6.0-2.spec
创建目标平台:i686-pc-solaris
正在创建目标:i686-pc-solaris
#

本例设定生成的RPM包适用的目标平台为:i686-pc-solaris(即体系为i686,平台为pc,操作
系统为solaris)。注意:必须在/usr/src/dist/RPMS目录下创建一个i686的子目录,没有指
定体系的子目录,RPM将无法生成软件包。我们可以查询一下生成的软件包,看其适用的体
系与操作系统是什么:

#rpm-qp--qf"archis%{arch}nosis%{os}n"/usr/src/dist/RPMS/i686/lze-6.0-2.i686.rp
m
archisi686
osissolaris
#

从输出上可以看到,其体系与操作系统正是我们所设定的。

5.--quiet:尽量减少信息输出
此选项的目的,是让RPM减少信息的输出。使用此选项后,如果没有错误发生,RPM就不会输
出多余的信息,这时的RPM也显得比较“安静”(quiet)了。
$rpm-bl--quietlze-6.0-2.spec
$

6.--clean:执行文件清理
如果软件包描述文件的清理段(%clean)没有删除临时文件的命令,那么RPM建包结束后那些
临时文件还是存在的,占用了一定的空间。如果想让RPM自动删除那些临时文件,可以在建
包时使用--clean选项。此选项执行一条命令,即:
rm-rf软件名-版本号

用它来删除"软件名-版本号"目录及该目录下的所有文件。这个"软件名-版本号"目录,也
即RPM默认的存放解压后的源程序的目录。
#rpm-bl--cleanlze-6.0-2.spec
Processingfiles:lze
FindingProvides:(using/usr/lib/rpm/find-provides)...
FindingRequires:(using/usr/lib/rpm/find-requires)...
Provides:lze-edit
PreReq:/bin/sh
Requires:/bin/shld-linux.so.2libc.so.6libc.so.6(GLIBC_2.0)libc.so.6(GLIBC_2.1)

Executing:--clean
+umask022
+cd/usr/src/dist/BUILD
+rm-rflze-6.0
+exit0

注:例中的“Executing:--clean”表示RPM开始执行自己的文件清理操作。

7.--rmsource:删除源程序及描述文件

此选项用于指示RPM在建包后删除软件源程序和包描述文件,软件源程序由包描述文件中的
Source域定义。此选项也可单独使用,如:
#rpm--rmsourcelze-6.0-2.spec
#lslze-6.0-2.spec../SOURCES/lze-6.0-2.src.tgz
ls:lze-6.0-2.spec:文件或目录不存在
ls:../SOURCES/lze-6.0-2.src.tgz:文件或目录不存在
#

8.--sign:软件包内置数字签名
此选项用于在软件包内添加PGP数字签名,通过数字签名,用户可以校验软件包是否原装,是
否修改过。要使用PGP数字签名,必须先安装好PGP应用程序及产生自己的密钥对。(有关数
字签名的内容,详见<<精通RPM之八--签名篇>>)

使用此选项建包时,RPM会要求输入密码,验证正确后开始执行建包的系列操作,在建包前会
产生数字签名,以便写入包中。请看下例:(省略不少输出,......表示)
#rpm-bb--signlze-6.0-2.spec
Enterpassphrase:mypass
Passphraseisgood.
Executing:%prep
......
Executing:%build
......
Executing:%install
......
Processingfiles:lze
......
Requires:/bin/shld-linux.so.2libc.so.6
Generatingsignature:1002
GeneratingsignatureusingPGP.
PrettyGoodPrivacy(tm)Version6.5.8
(c)1999NetworkAssociatesInc.
UsestheRSAREF(tm)Toolkit,whichiscopyrightRSADataSecurity,Inc.
ExportofthissoftwaremayberestrictedbytheU.S.government. Wrote:/root/test/RPMS/
i386/lze-6.0-2.i386.rpm
Executing:%clean
......
#

注:例中要求输入密码,输入mypass后校验成功,之后RPM开始建包操作。(实际上,mypass在
屏幕上并不显示出来)例中的Generatingsignature之下的几行就是产生数字签名时输出的
东西。

其它建包相关的命令

其它建包相关的命令有两个,它们都是针对RPM格式的源码包进行操作的,执行时先安装源
码包,然后再根据软件包描述文件进行下一步的工作。 1.重编译命令:
用法为:rpm--recompileRPM源码包1RPM源码包2...
如:
rpm--recompilelze-6.0-2.src.rpm

此命令执行时,首先安装此源码包,然后依次执行源码包内软件包描述文件的预处理段
(%prep),编译段(%build),安装段(%install)的脚本程序。此命令相当于以下两条命令:

1)rpm-ilze-6.0-2.src.rpm
2)rpm-bilze-6.0-2.spec

2.重建立命令:
用法为:rpm--rebuildRPM源码包1RPM源码包2...
如:
rpm--rebuildlze-6.0-2.src.rpm

重编译命令执行后并不建立新的RPM软件包,而此重建立命令执行后则会制作出一个新的
RPM软件包。重建立命令执行时,首先安装RPM源码包,然后依次执行源码包内软件包描述文
件的预处理段(%prep),编译段(%build),安装段(%install),清理段(%clean)的脚本程序,
生成一个新的RPM执行包,最后删除源程序包,描述文件及其它临时文件。此命令相当于以
下两条命令:
1)rpm-ilze-6.0-2.src.rpm
2)rpm-bb--clean--resourcelze-6.0-2.spec


--


我每天花十二个小时上网   一个小时玩CS      所以
六个小时睡觉             一个小时吃饭      …………
三个小时玩Linux          一个小时闲逛      我没女友

※ 来源:·北大未名站 bbs.pku.edu.cn·[FROM: 162.105.40.16]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店