RPM打包探索(rpm-max翻译整理)

1. %global 和 %define 的区别?
这是内置宏,%define用来定义宏,%global用来定义一个全局可见的宏(在整个spec文件中可见)
2. %{!?macro-name} 和 %{?!macro-name} 的区别?


3. rpmbuild 宏定义文件都有哪些?加载顺序如何?


4. AutoReqProv 的作用?


5. 宏定义 %define kernel_variant_post(v:r:) 中 v:r: 的意思?


####
1. Shell 脚本


2. Makefile




rpm包的构建
rpm有一个比较官方的网站解释一系列和rpm包有关的的文档;我主要从第10章开始学习。
参考网站: http://www.rpm.org/max-rpm/index.html


第一部分:


1.如何创建一个spec文件?
  我们管理RPM构建过程的方式是创建spec文件,规范文件包含八个不同的部分,其中大部分是必需的。
  下面我们浏览每个部分并创建一个实例包cdplayer作为我们的规范文件。
  
  The Preamble(我们暂时理解为序言吧!!) 
  前序:
序言中包含了大量的关于构建包的信息以及构造者。下面是cdplayer包的序言:


====================================================================
#
# Example spec file for cdplayer app...
#
Summary: A CD player app that rocks!
Name: cdplayer
Version: 1.0
Release: 1
Copyright: GPL
Group: Applications/Sound
Source: ftp://ftp.gnomovision.com/pub/cdplayer/cdplayer-1.0.tgz
URL: http://www.gnomovision.com/cdplayer/cdplayer.html
Distribution: WSS Linux
Vendor: White Socks Software, Inc.
Packager: Santa Claus <sclaus@northpole.com>


%description
It slices!  It dices!  It's a CD player app that
can't be beat.  By using the resonant frequency
of the CD itself, it is able to simulate 20X
oversampling.  This leads to sound quality that
cannot be equaled with more mundane software...
======================================================================


一般来说,序言由条目,每行一个开始标记,后跟一个冒号,然后是一些信息。
例如,每行从“Summary:”开始给了一个简短的可以被RPM显示的描述。
当然每行的顺序并不重要,只要他们出现在序言中。


下面我么来一睹每一行的作用:
---Name  
#name这行的定义实际会被调用。总的来说,这样做比较好因为软件的名称也将包含在包标签,和包的文件名。


---Version
#设置软件包的版本号,将被包含在包的标签和包文件名中。


---Release
#Release 是一种用于表示软件(目前的版本已经打包的)被发布次数的数量,
你可以认为它是包的版本号。Release也包标签和包文件名的一部分。


---Copyright
# 表示版权信息


---Group
#Group行是用于保存一串字符串,它定义了应该如何分组打包软件与其他包。
字符串包含了一系列的单词用斜杠隔开。从左到右,这句话描述的打包软件更加明确一些。
上面我们分组cdplayer应用程序,因为它是一个应用程序,然后与声音有关的应用程序。


---Source
#Source这一行主要有两个作用:
   --记录包的来源和给出包名(废话!!)
---URL
#和Source有点像


---Distribution
#Distribution行包含产品的名称,是软件的一部分。在Linux世界中,操作系统通常是
打包成一个“distribution”,所以因此而得名!!!


---Vendor
##供应商表示,个人用户可以省略!!


---Packager
#打包者的信息,具体人或者责任人。


---Description
#Description行由一个百分号'%'开始,这实际上是spec宏定义的方式。
在后面我们知道spec文件的宏定义是百分号'%' 开头的。和其他行不同的是这里可以是多行,
来提供更具体的描述信息相较于Summary


---A Comment on Comments --注解
#在spec文件的开始以‘#’开头的是解释,这可以让文件更加容易理解!!




---The %prep Section
---准备部分
#在序言部分,我们提供了丰富的信息。大多数的这些信息是给人来看的。
只有名称、版本、发布以及源和包构建过程有直接关系。
然而,在%prep部分重点是指导RPM准备软件构建(%build)的过程。


%prep阶段,创建软件的构建环境,开始删除任何之前的构建留下的残余。在这之后,扩展源文件。
下面是一个实例%prep部分:
=========================================================================
            %prep
            rm -rf $RPM_BUILD_DIR/cdplayer-1.0
            zcat $RPM_SOURCE_DIR/cdplayer-1.0.tgz | tar -xvf -
=========================================================================


   %prep部分看起来酷似一个脚本,为什么呢?因为本来就是脚本!!!这里可以使用任何shell脚本,
包括一些环境变量(比如RPM的一些内置宏$RPM_BUILD_DIR ),和管道命令等。


在这一阶段,我们在构建目录中执行递归删除任何旧的构建。然后我们将gzip tar文件解压缩,
并提取其内容到构建目录中。


通常,源文件可能需要打patch。%prep部分是打补丁最合适的地方,但是在本例中我们没有看到补丁,
因为暂时不需要补丁。别担心,哈哈!!后面我们会讨论和补丁以及它的“骄傲”哈哈。
在较为复杂一点的包构建时。


---Making Life Easier With Macros 
---宏,让你的生活变得更简单!!!
我们已经在是你在上面描述的宏%prep并不难理解,宏可以有效降低编译一些复杂包的难度,下面
我们将介绍宏%setup。


平均来讲使用tar来归档解压文件是%setup宏的主要营生。就像像之前我们将的%prep宏部分,在
这一阶段%setup宏将clean掉之前的构建树以及解压提取所需文件从源文件中。
当然%setup宏还有一些选项,我们将在后面的章节来描述。
      ===================
      | %prep
      | %setup
      ====================
上面是一个非常简单的%prep部分,我们也使用%setup来替代那些脚本。%setup宏还有很多的选项来
处理不同的情形,关于更多的这个宏的描述我们将在后面说明。
在我们的例子中,关于%prep部分描述就到这里,下面我们将介绍实际的构建build。


----The %build Section
----%build部分
一点也不奇怪,下面这部分就是spec文件负责构建的部分---%build sectio;就像前面的%prep宏部分,
这部分也是一段普通的shell脚本。不同的是,这里没有宏。原因是软件的build过程是非常简单的或者
高复杂度的。在后一种情况下宏帮不上什么忙。在我们例子中build的过程是很easy的。
       ================
       | %build
       |  make
       ================
先和make的实用说声谢谢!!!我们只需要一个命令就可以构建cdplayer应用。
在应用程序的build部分比较难搞的情况下,build 部分才比较有意思(这不是我说的@)!!!


-----The %install Section
----- %install 部分
这部分就是执行相关的shell脚本,和前面的%prep和%setup类似。如果应用程序在build的时候
makefile中就install这个‘target’的话,%install部分将会万里无云的般的顺畅。我们例子就是。
==================
| %install
| make install
==================
但是如果应用程序没有自动安装的本事,还需要麻烦你去写个脚本来做这件事情。脚本放在%install下就OK了!




-----The %files Section
-----%files部分
嗯,%files部分和其他部分稍有不同的是,在files中包含了包的一部分。记住了--如果没在文件列表
里的文件将不会被放进软件包中。
=======================
%files
%doc README
/usr/local/bin/cdp
/usr/local/bin/cdplay
/usr/local/man/man1/cdp.1
=======================
上面%doc开头的行表示RPM处理不同文件的类型。我们可以猜到,%doc代表文档相关的。
这里将被用于标记这文件的是文档。在上面的例子中,EADME文件将被放到指定的目录
中,关于具体在哪里要看Makefile文件中的指定。这里详细的解释会在后面继续说明。。


怎么来创建file list呢??
虽然从各方面来看RPM是一个自动化软件安装,很容易迷糊的是你会觉得RPM将为你大包大揽
做了所有事情。不是这样地!!创建file list仍然是一个手动的过程,虽然它似乎乍一看,
它可以自动从某种意义上讲,它实际上比看起来更困难的问题。


因为很多应用的files是被Makefile来安装的,RPM没有在build中起作用,但是不能判断哪些文件
是包的一部分。有人尝试使用修改版本的logs名来安装每个文件???
但是也不是所有的Makefile都是用install,就算有,也很少使用。


Another approach tried was to obtain a list of every file on the build system, 
immediately before and after a build, and use the differences as the file list. 
While this approach will certainly find every file that the application installed, 
it can also pick up extraneous files, such as system logs, files in /tmp, and the like. 
The only way to begin to make this approach workable would be to do nothing else on the build system, 
which is highly inconvenient. This approach also precludes building more than one package on the system at any given time.
上面我还没有明白??


现如今,创建file list最好的办法就是阅读Makefile文件,看哪些文件将被install,核实这些文件的安装在构建系统上,并创建列表。


*****The Missing Spec File Section
***** 还有那些部分在spec文件中??
上面的那个例子实在是有点简单了,所以我么漏掉了两个部分,这两部分在一些较为
复杂的情况下可能会用到。后面lou一眼,跟多详细的部分在后面专门讨论!!


------The Install/Uninstall Scripts
------安装和卸载脚本
这两个脚本将被执行在下面的情况下:
#包被安装之前
#包被安装之后
#包被卸载之前
#包被卸载之后
我们会在后面看到这些脚本的使用;


-----The %clean Section
-----%clean 部分
另一个被忘记的部分就是这里,这部分可以用来清理任何文件不属于正常构建的应用程序的区域。
比如一些/tmp下的临时文件。


NOTE:更多关于环境变量相关的使用可以看构建时的脚本。




第二部分:
2.开始构建---Starting the Build


************待完善!!!




第三部分:
这些内容根据对max-rpm-snapshot的理解整理而来;
------------rpmbuild的参数说明-------------
1. rpmbuild -b<stage> options file1.spec … fileN.spec
 ---在使用这个命令的过程中我们可以先rpmbuild --help了解一下具体有哪些参数,根据这参数在不通过
 阶段的使用以及对这一过程中相关调试的辅助选项的理解。
 
 --我们知道在构建rpm包的过程中有5大部分,rpmbuild命令为我们提供参数选项可以针对你指定的某一部分
 后者几个部分来执行构建命令。如下面的选项和解释所示:
 ---------------------------------------------------------------------
 -------<stage>-----------
 p Execute %prep  只执行prep部分;
 c Execute %prep, %build   执行prep和build部分但没有install等部分;
 i Execute %prep, %build, %install, %check
 b Execute %prep, %build, %install, %check, package (bin)--相对‘-a’参数,少了构建源码包
 a  Execute %prep, %build, %install, %check, package (bin, src)
 l Check %files list
 注意事项:check阶段在很多实用中不为常用;
 ---------------------------------------------------------------------
 #以上为<stage>参数选项的说明,下面对options作了说明;
 我们从上面的描述可以知道,我们可以指定参数对构建的具体阶段部分,我们也可以用在这一基础上
 实用一些选项来更加方便的为我们的包构建部分服务;
 
 -------------------------------------------------------------------------------------
 ****************Options********************
 --short-circuit Force build to start at particular stage (-bc, -bi only) 这个选项可以为-bc, -bi
    阶段的构建强制执行从那个阶段开始;
 --test Create, save build scripts for review  --这一参数有利于我们对构建包过程中各个阶段
  使用脚本的情况具体的了解(但是我在我的系统上没有找到这选项,难道这是骗人的!!!感觉这个选项是很有用的)
  
***--clean Clean up after build  构建完成之后移除构建时的目录文件。例如:
     rpmbuild -bp --clean xxx.spec  可以在直定阶段使用这一参数;


*** --sign Add a digital signature to the package    此参数执行可以为构建的包添加一个数字签名
                                                  签名使用的PGP或者GPG,根据不同版本而定;
----buildroot <root> Execute %install using <root> as the root  指定安装路径,改变默认的安装路径
    这个参数在使用的过程中要注意两个地:
1--在spec文件中的指定BuildRoot:/tmp/foo ;
2--如果你的是用make来install,那么make的指定安装目录在spec文件中;
%install
make ROOT="$RPM_BUILD_ROOT" install


--buildarch <arch> Perform build for the <arch> architecture  这个参数也已经找不到了,但是他被‘--target’代替
--rcfile <rcfile> — Set alternate(替换) rpmrc file to <rcfile> 使用指定的文件读取宏,不适用默认文件(/usr/lib/rpm/rpmrc)
 
 -------------------------------------------------------------------------------------
 
-----------------rpmbuild ----做些什么呢??
当你使用‘-b’选项时,一个包的构建就开始了。其余的命令参数选项用来精确控制构建那个阶段,下面我们来看:
一个完整的RPM build命令应该至少包含两部分信息:
1.spec文件; 2.你希望构建到哪各阶段;
在之前的讨论中或者你已经从其他途径了解到RPM的构建有好几个阶段部分,而且可以由命令参数来决定构建到那个阶段;你可以轻松的查看
构建的过程等;


*******选项:rpmbuild -bp — Execute %prep --只执行prep(准备阶段)
---我们知道rpmbuild -bp 表示指定RPM构建的第一阶段(stage),在spec文件中由标签宏%prep来标记,在这一阶段所做的事情在文章的前面已经讨论;


下面来看这个简单的例子中执行过程:
------------------------------------------------------------------------
# rpmbuild -bp cdplayer-1.0.spec
* Package: cdplayer
Executing(%prep):
+ umask 022
+ cd /usr/src/redhat/BUILD
+ cd /usr/src/redhat/BUILD
+ rm -rf cdplayer-1.0
+ gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz
+ tar -xvvf -
drwxrwxr-x root/users        0 Aug  4 22:30 1996 cdplayer-1.0/
-rw-r--r-- root/users    17982 Nov 10 01:10 1995 cdplayer-1.0/COPYING
-rw-r--r-- root/users      627 Nov 10 01:10 1995 cdplayer-1.0/ChangeLog

-rw-r--r-- root/users     2806 Nov 10 01:10 1995 cdplayer-1.0/volume.c
-rw-r--r-- root/users     1515 Nov 10 01:10 1995 cdplayer-1.0/volume.h
+ [ 0 -ne 0 ]
+ cd cdplayer-1.0
+ cd /usr/src/redhat/BUILD/cdplayer-1.0
+ chown -R root.root .
+ chmod -R a+rX,g-w,o-w .
+ exit 0

-----------------------------------------------------------------------------        
--在%prep部分包含一个%setup宏,首先RPM确定cdplayer使我们要构建的目标,然后他设置umask并启动%prep部分,
在这里,%setup主要切换目录和移除之前的构建遗留文件。
---接下来%setup 来释放已归档的源文件并用tar来创建构建目录树。移除已经完成的文件。
---最后,%setup切换到cdplayer的构建目录树并改变文件属主和适当的文件权限。exit 0 表示到了%prep的最后阶段;
   所以当我们使用‘-bp’参数时,RPM就在这里终止构建,我们可以看一下再BUILD中留下来的构建目录文件。
-----------------------------------------------------------------


# cd /usr/src/redhat/BUILD   值得注意的是,在新版的rpmbuild已经改换这一目录到用户家目录下
# ls -l
total 1
drwxr-xr-x   2 root     root         1024 Aug  4 22:30 cdplayer-1.0
------------------------------------------------------------------
比如我的机子上:/home/zhongtian/rpmbuild/BUILD/
[zhongtian@localhost BUILD]$ ls
kernel-3.10.0-123.ns6
----这就是我们构建的顶层目录,切换到cdplayer-1.0为源码所在;
--------------------------------------------------------------------
# cd cdplayer-1.0
# ls -lF
total 216
-rw-r--r--   1 root     root        17982 Nov 10  1995 COPYING
-rw-r--r--   1 root     root          627 Nov 10  1995 ChangeLog

-rw-r--r--   1 root     root         2806 Nov 10  1995 volume.c
-rw-r--r--   1 root     root         1515 Nov 10  1995 volume.h

-------------------------------------------------------------------
我们可以清楚的看到在%setup中chown和chmod命令所做的改动---所述用户和组都为root,
 将相关的组的写权限禁用等;(一个恰到好处的权限改动是非常必要的);
 
================================================= 
****选项:rpmbuild -bc — Execute %prep, %build


----我们如果不在构建中使用'-bp'命令选项,RPM会在软件包构建完成之后停止。在
spec文件中的所有%build部分命令都将被执行,下面的例子中我们先将%prep部分的输出去掉来看%build部分,
需要明白的是,尽管如此他还是执行了(%prep);
------------------------------------------------------------------------------------
# rpmbuild -bc cdplayer-1.0.spec
* Package: cdplayer
Executing(%prep):

+ exit 0
Executing(%build):
+ cd /usr/src/redhat/BUILD
+ cd cdplayer-1.0
+ make
gcc -Wall -O2  -c -I/usr/include/ncurses  cdp.c 
gcc -Wall -O2  -c -I/usr/include/ncurses  color.c 
gcc -Wall -O2  -c -I/usr/include/ncurses  display.c 
gcc -Wall -O2  -c -I/usr/include/ncurses  misc.c 
gcc -Wall -O2  -c -I/usr/include/ncurses  volume.c 
volume.c: In function `mix_set_volume':
volume.c:67: warning: implicit declaration of function `ioctl'
gcc -Wall -O2  -c -I/usr/include/ncurses  hardware.c 
gcc -Wall -O2  -c -I/usr/include/ncurses  database.c 
gcc -Wall -O2  -c -I/usr/include/ncurses  getline.c 
gcc -o cdp cdp.o color.o display.o misc.o volume.o hardware.o database.o
getline.o  -I/usr/include/ncurses  -L/usr/lib -lncurses
groff -Tascii -man cdp.1 | compress >cdp.1.Z
+ exit 0



-------------------------------------------------------------------------------------
当执行上面的命令后,我们看到RPM首先执行%prep阶段部分(因为篇幅关系省略);接下来
RPM开始执行%build阶段部分并在groff命令之后结束,完成了%build部分的全部构建;
--我们spec文件中的%build部分如下:
----------------------------------------------------
%build
 make
----------------------------------------------------
但是在输出信息中我们看到在make命令之前,RPM首先切换目录进入BUILD,然后RPM开始执行make并在
grooff命令之后完成%build部分。因为我们使用'-bc'参数选项,RPM在这里停止(这可以追踪到RPM的实现的源码中)


---下一个构建阶段是install新构建的软件,这一部分工作由spec文件中%install(和%check)阶段部分来完成,
RPM可以使用命令参数选项‘-bi’来停止在install完成之后。
==============================


*********选项:rpmbuild -bi — Execute %prep, %build, %install, %check
---使用选项‘-bi’之后,RPM将在软件完全完成构建、安装、以及测试之后停下来。看一下下面的输出:


----------------------------------------------------------
# rpmbuild -bi cdplayer-1.0.spec
* Package: cdplayer
Executing(%prep):

+ exit 0
Executing(%build):

+ exit 0
Executing(%install):
+ cd /usr/src/redhat/BUILD
+ cd cdplayer-1.0
+ make install
chmod 755 cdp
chmod 644 cdp.1.Z
cp cdp /usr/local/bin
ln -s /usr/local/bin/cdp /usr/local/bin/cdplay
cp cdp.1 /usr/local/man/man1
+ exit 0
Executing(%check):
+ umask 022
+ cd /usr/src/redhat/BUILD
+ cd cdplayer-1.0
+ make test
All tests run successfully.
+ exit 0
Executing(%doc):
+ cd /usr/src/redhat/BUILD
+ cd cdplayer-1.0
+ DOCDIR=//usr/doc/cdplayer-1.0-1
+ rm -rf //usr/doc/cdplayer-1.0-1
+ mkdir -p //usr/doc/cdplayer-1.0-1
+ cp -ar README //usr/doc/cdplayer-1.0-1
+ exit 0

----------------------------------------------------------
在下面单独列出我们的例子中的%install部分:
----------------------
%install
 make install
-------------------------
--我们已经知道在完成了%prep和%build部分的构建之后%install部分开始执行。来看一下输出信息,
我们看到RPM切换目录到BUILD然后执行make install命令(这是唯一在%install部分的命令)。
输出信息从make install 开始到最近的exit 0完成是make install的输出。
--下一阶段部分%check的只有唯一的命令make test 。在剩余的命令就是spec文件中的%files部分内容。
来看一下:
---------------------------
%files
%doc README
/usr/local/bin/cdp
/usr/local/bin/cdplay
/usr/local/man/man1/cdp.1
---------------------------
%doc README这一行就是文本相关。%doc这个标记可以识别文件是文档。RPM处理文档文件的方式是,创建一个doc
目录来放置文档。做完这些事情就到了最后的的‘exit 0’了(表示%install部分的终结)。原因为‘-bi’选项的返回值所致;


--下面的部分构建执行的过程知道二进制软件包被创建出来之后RPM才会停止;这是由命令选项‘-bb’所为;


*****选项:rpmbuild -bb — Execute %prep, %build, %install, %check, package (bin)--(二进制软件)
------------------------------------------------------------------------------------
# rpmbuild -bb cdplayer-1.0.spec
* Package: cdplayer
Executing(%prep):

+ exit 0
Executing(%build):

+ exit 0
Executing(%install):

+ exit 0
Executing(%check):

+ exit 0
Executing(%doc):

+ exit 0
Binary Packaging: cdplayer-1.0-1
Finding dependencies...
Requires (2): libc.so.5 libncurses.so.2.0
usr/doc/cdplayer-1.0-1
usr/doc/cdplayer-1.0-1/README
usr/local/bin/cdp
usr/local/bin/cdplay
usr/local/man/man1/cdp.1
93 blocks
Generating signature: 0
Wrote: /usr/src/redhat/RPMS/i386/cdplayer-1.0-1.i386.rpm
Executing(%clean):
+ umask 022
+ cd /usr/src/redhat/BUILD
+ cd cdplayer-1.0
+ exit 0

------------------------------------------------------------------------------------
---来看,当执行完成 %prep, %build, %install, and %check 部分和处理一些特定的文档之后,RPM创建了一个
二进制包。在上面的输出信息中我们发现RPM首先执行自动依赖检查。做检查是为了那些确定动态库被可执行程序需要。
接下来,RPM将文件打包并输出最终的‘产品’软件包。最后在做一些移除临时文件的工作。


******选项:rpmbuild -ba — Execute %prep, %build, %install, %check, package (bin, src)
---这一选项驱使RPM执行所有的构建的阶段;在这一个命令后面,RPM做了如下事情:
   <1> 解源码包;<2>打patch(如果需要的话);<3>编译软件 <4>安装软件 <5>运行test检查软件;
   <6>创建二进制软件包<7>创建源码包<cdplayer.src.rpm>;
---上面这一过程只需要一个命令就解决了!!!下面是执行之后的动作:
-----------------------------------------------------------------------------------------------


# rpmbuild -ba cdplayer-1.0.spec
* Package: cdplayer
Executing(%prep):

+ exit 0
Executing(%build):

+ exit 0
Executing(%install):

+ exit 0
Executing(%check):

+ exit 0
Executing(%doc):

+ exit 0
Binary Packaging: cdplayer-1.0-1

Executing(%clean):

+ exit 0
Source Packaging: cdplayer-1.0-1
cdplayer-1.0.spec
cdplayer-1.0.tgz
80 blocks
Generating signature: 0
Wrote: /usr/src/redhat/SRPMS/cdplayer-1.0-1.src.rpm
#
-----------------------------------------------------------------------------------------------
--在前面的例子中RPM执行一系列的各个阶段以及处理文档信息创建二进制包并且清除动作;
--在最后一步创建源码包。由输出信息可以看到它包含了spec文件和源文件(也可能包含一个或者多个patch文件,例子中没有使用patch)。
--在‘-ba’参数的命令执行完成后构建和打包(二进制和源码包)成功。然而这里还有一些构建过程中可以使用的命令
参数选项。比如'-bl'参数:


*******选项:rpmbuild -bl — Check %files list
前面的描述中选项的命令的选项的最后一个字母指定rpm的动作通知在那个阶段,但是不同的是,如果加入‘l’参数,下面饿检查都要被执行:
   <1>扩展spec文件中的%files 列表这个宏,检查每个文件是否真实存在;
   <2>确定软件需要的动态库检查每一个可执行文件列表;
   <3>确定那个动态库应该有包来提供;
----为什么必须要做这些检测?什么情况会用到?需要牢记的是%files 列表必须是手工创建的。使用'-bl'选项时夏敏的步骤
  是必须的:
  **写文件列表的%fiels; 
  **使用‘-bl’选项检测;
  **作必要的改动对%files 列表;
这个过程可能会发生多次迭代,但是最终会通过检查。所以说使用‘-bl’选项来检测文件列表肯定比你花了两个小时去构建最后发现写错了文件名要值得!!
看这个使用‘-bl’例子:
-----------------------------------------------------------
# rpmbuild -bl cdplayer-1.0.spec
* Package: cdplayer
File List Check: cdplayer-1.0-1
Finding dependencies...
Requires (2): libc.so.5 libncurses.so.2.0
#
-------------------------------------------------------------




****选项:--quiet — Produce as Little Output as Possible 让输出信息尽量少;


****选项:--rcfile <rcfile> — Set alternate rpmrc file to <rcfile> 使用指定文件中的宏;


--除了上面介绍的还有另外你哥常用的与build相关的命令选项;




在开启新的篇章:这一片参考charter 13,主要描述spec文件中的一些细节;


****************************Inside the Spec File 漫游spec*********************
在这一章的介绍中,我们将带你详细的浏览spec文件。spec文件是由不同类型的条目构成,我们来看看:
** Comments — Human-readable notes ignored by RPM. 这里指给人看的注释信息
** Tags — Define data   定义数据--???
** Scripts  -- Contain commands to be executed at specific times --包含在制定的时间(阶段)执行的命令;
** Macros — A method of executing multiple commands easily.   --执行多个命令的一种方法(make life easy!!)
** The %files list — A list of files to be included in the package.---包中包含的文件列表
** Directives — Used in the %files list to direct RPM to handle certain files in a specific way. --在files中处理文件的一种方式
** Conditionals — Permit operating system- or architecture-specific preprocessing of the spec file.--允许操作系统和指定架构的预处理spec文件


--Comments 就是由‘#’号起始的行(与shell类似),可以放置在任何位置;注释spec的宏是要在使用‘#%%’:
  #%%vendorname


-- Tags ---这里说是数据的定义:
格式为:<something>:<something-else>  这里的前半部分是指Tag,被用来命名或者标记;后半部分用分号‘:’来隔开表示要表达的意思;
Tag一般出现在spec文件的顶部的序言部分(preamble),比如:
Vendor:vendorname, Inc.
--在上面的例子中Tag就是“Vendor”。Tag没有大小写之分,既可以全是大写;或者全是小写;或者大小写都有
“Vendor”在这里表示公司名称,所指定的数据就是“vendorname, Inc.”
---------------------------------------------------------
VeNdOr : White Socks Software, Inc.
vendor:White Socks Software, Inc.
VENDOR    :    White Socks Software, Inc.
---------------------------------------------------------
上面的写法似乎很是没有底线,但是我觉得还是有点底线的好哈哈!!但是不管你将Tag搞的看起来多么整洁或者丑陋---RPM才懒得管这么多。
但是,着说但是了,注意你必须将Tag后面的数据以特定格式组织起来(你总不希望别人看到你写的东西那么刺眼吧)。


******包名的Tags
<name>-<version>-<release>  --最后用来命名你的软件包;格式就是如此;
--自然的这三个标签(tags)就是名称、版本、发布次数;
--我们分解这三部分来看看:
--name--定义被名称,多数情况下使用的name和打包的软件的名称应该在拼写上是相同的;
name 中不能有空格,否则空格前面的部分被认为是name;例如:Name: cdplayer


--版本的Tags
定义包的版本信息,version的命名尽量能和源版本的格式相近;这个命名一般不会出现问题,因为修改这一部分的
分一般都是原版本的开发者,他们熟悉这过程;但是有一个规定就是这里不能使用破折号“-”,如果你误用,RPM会提醒你:
---------------------------------------------------
# rpmbuild -ba cdplayer-1.0.spec
* Package: cdplayer
Illegal '-' char in version: 1.0-a
#
----------------------------------------------------
但是在我的试验中没有报错!!!!!(这篇文章是有点过时,但还好只是少部分!!),还有空格等等不要用!!


--The release Tag 发布次数,如果这个软件包是第一次打包发布,那么realse:1,否则在前面的基础上加一增长;


******描述 Tags 
这个tag主要提供一些打包者的信息和包的信息;
The %description Tag 用来更加深入的描述软件包的信息。大概几句话的描述内容,告诉用户软件的作用功能等;
描述tag的格式比较简单,在%description下面具体的描述就ok!
------------------------------------------------------------------------
%description
It slices!  It dices!  It's a CD player app that can't be beat.  By using
the resonant frequency of the CD itself, it is able to simulate 20X
oversampling.  This leads to sound quality that cannot be equaled with
more mundane software...
-------------------------------------------------------------------------
注意:和其他tag不同的是,描述tags由一个'%'起始,而且可以是多行;如果一行是空的话,那么空白行上下的文本
段将被RPM格式化为两个段落;多行中的每一行的开头如果是空格的话,那么RPM会认为这几行都是一个段落的;比如:
------------------------------------------------------------
%description
 It slices!
 It dices!
 It's a CD player app that can't be beat.
By using the resonant frequency of the CD itself, it is able to simulate
20X oversampling.  This leads to sound quality that cannot be equaled with
more mundane software...
-------------------------------------------------------------
上面的例子中开始的三行家会被RPM逐字的显示(因为这三行都是以空格开头),剩余的文本会被RPM处理,
最终他们都被认为是一个段落而处理;(RPM这一点体现了什么呢???呵呵)


哈哈!!再来看下面的例子,其中有一行是空白行,那么他最终会被认为是两个段落,由空白行来separate;
---------------------------------------------------------------------------------------------------
%description
 It slices!
 It dices!
 It's a CD player app that can't be beat.


By using the resonant frequency of the CD itself, it is able to simulate
20X oversampling.  This leads to sound quality that cannot be equaled with
more mundane software...         
---------------------------------------------------------------------------------------------------


--The summary Tag 总结tag,总的来描述一下软件包,只能是一行;
   ------------------------------------
   Summary: A CD player app that rocks!
   -----------------------------------
--The license Tag 所遵循的协议 --License: GPL


--The distribution Tag  ---用来定义一组包


--The icon Tag   --图标 Icon: foo.xpm


--The url Tag  ---站点信息
URL: http://www.gnomovision.com/cdplayer.html


--The group Tag  
用于将类型或者功能相近的包组织在一起,有点像目录的感觉,将一些功能或者类型相似的文件组织起来,比如文档类的、系统类的、调试类的、应用类等:
Group: Documentation
Group: Development/System
Group: Development/Debug
Group: Applications/Editors
Group: Applications/Spreadsheets
后面两个表示在Applications下面会有连个编辑软件,或者其他编辑软件;


--The packager Tag 定义一些开发者的名字或者联系信息,可以使人名、公司名、Email或者电话,maybe 客户会给你
送钱来或者打骚扰电话亦或是恐吓信(⊙o⊙)哦!!!开个玩耍!!
Packager: zhongtian <zhongtianemail@gmail.com>   ---我也许会回复你哦!!




*****Dependency Tags 依赖tag*****************


--RPM的一个特性就是确保一个包如果安装那么系统环境中需要提供这个报所需要的所有东西!!同样,如果一个包被卸载必须确保没有其他包依赖
要卸载的包。这种依赖功能非常有用对于终端用户来安装或者卸载;
--然而,为了RPM能够得到更多的依赖信息,打包者必须对包添加合适的依赖信息。需要注意的是,添加一来信息
要’深谋远虑‘;下面我么来看看依赖相关的tags。更加具体的讨论将在后面《Adding Dependency Information to a Package》中列出;


来看看第一个依赖tag:
--The provides Tag  
这个tag用于指定一个虚拟包(一个打包的软件)安装时提供。一般来说,这个tag用来为不同的提供相同的服务。
比如说,一个包为允许用户阅读邮件提供了mail-reader虚拟包。另外一个包也依赖阅读邮件这个虚拟包。这样的情况下
安装不会出现问题,如果一个邮件阅读的程序被安装。一睹为快:
Provides: mail-reader


--The requires Tag 
这个requires标记tag被用来提醒RPM,软件包正常运行所需要的其它必要的功能。这个功能也就是指另一个包的名字,或者是
之前提起的虚拟包来提供一个或者多个包所要使用的Provides 标签。当requries 标签引用一个包名时,版本的比较也应该被包含
在包名中使用一些范围符号,比如:<, >, =, >=, or <=, 这些符号。例如:
--------------------------------------------------------------
Requires: playmidi = 2.3
--------------------------------------------------------------
如果requires 标签需要与下面定义的epoch 标签最比对,应该写成下面格式:
--------------------------------------------------------------
Requires: playmidi >= 4:2.3
Epoch: 4
--------------------------------------------------------------


--The conflicts Tag  
  这个标签字面意思是冲突相关的标签,他其实是对requires标签的一个补充。我们通过上面的学习知道,requires标签被用于指定什么包必须准备好
以保证当前安装的包能顺利安装。而conflicts标签则是指为了当前包的正常执行,那些包不能被安装,和requires标签互补。
  conflicts标签的格式和requires相同,标签后面更随一个真实的或者虚拟的包名称。
----------------------------------
Conflicts: playmidi = 2.3-1          
----------------------------------
也可以和requires标签类似在和epoch标签作比较:
Conflicts: playmidi = 4:


--The epoch Tag   #这个用的不太多???先绕过不解释!!!




----The autoreqprov, autoreq, and autoprov Tags 
这几个标签用来控制软件包构建过程中的自动依赖过程。一般来说,在包构建过程中有下面几个过程被执行:
<1>所有可执行程序和共享库被打包分析以决定他们所需要的共享库可解析器。
<2>每个共享库的soname被自动加进包列表的“provides”信息中。
<3>所需的Perl脚本模块和被打包的模块都被自动添加到包的需求。
通过此操作,RPM帮助包的构建者节约了手工添加依赖的信息量。然而(好多的然而,有人的地方就由然而!!)
有些时候自动以来过程并不如你所愿(这就是悲剧哈)。在这种情况下 autoreqprov, autoreq, and autoprov tags 标签可以用来
disable自动依赖处理。autoreqprov--指完全禁用, autoreq --指仅提供需求, autoprov ---指仅支持“provides”
--来看看怎么写:
<1>需要和提供都禁用使用:AutoReqProv: no 
<2>只禁用需要使用:AutoReq: no
<3>只禁用"provides" 使用:AutoPro: no
--也可以使用数字0来代替字符‘no’ ;尽管RPM默认处理自动依赖的过程,但是受到autoreqprov, autoreq, and autoprov tags标签的影响
(把‘no’变为‘yes’或者把数字‘0’替换为数字‘1’)


******Architecture- and Operating System-Specific Tags  与操作系统有关的特定的标签
--伴随着RPM的受到广大用户的欢迎,有人希望在不同的计算机系统上使用它。当然这不会有什么问题,但是当下面两种情况发生时
事情开始变的有点棘手。
<1>一个特定的操作系统被移植到不同的硬件平台或者架构上;
<2>一个特定的体系结构上跑了不同的操作系统;
--真正的打击是当RPM被用来在不同的系统环境下打包软件时。没有方法控制构建的过程基于不同的架构和系统,打包者就必须为不同的
架构和操作系统开发软件包确实是很难。而唯一令人感觉快要奔溃的做法就是维护一个并行的RPM构建环境并接受所有的协调。但是,哈!!
--但是,看好了,幸运的是,RPM让这一切变得非常简单。使用下面的这些标签可以支持在多个环境下构建软件包,而所有的这一切
只是用了一个源码、patches和一个spec文件。(又来了,你是不是很受不了,但是没办法,为了行文简介)在多平台多架构上构建
RPM包的更加完善的讨论,将在后面的章节给出,请看《Chapter 19. Building Packages for Multiple Architectures and Operating Systems》


--The excludearch Tag  
标签 excludearch 保证让RPM不去尝试被排除的平台架构上打包;为什么要阻止包构建的原因是:
<1>软件还没有移植到被排除的架构上;
<2>软件在被排除的架构上没有意义;
--举个例子,软件本来是基于32位的,很显然,在64位机器上该被排除。
--第二个例子,软件是包含一个底层特性的架构专用,所以在不同的架构上应该被排除;比如说汇编程序;
--排除一个或者多个架构在 excludearch 标签后面,多个架构用空格或者逗号隔开表示;
例如: 
---------------------------------------
ExcludeArch: sparc alpha mips
---------------------------------------
在这个例子中RPM将不会尝试在SUN 的SPARC 、alpha 或者mips平台架构上运行;如果你在这其中的某一个架构上
运行构建命令,则将失败:
-------------------------------------------------------------------
# rpmbuild -ba cdplayer-1.0.spec
Arch mismatch!
cdplayer-1.0.spec doesn't build on this architecture
#
------------------------------------------------------------------
注意,如果你的意图是只在某一个指定平台架构上构建,可以使用 exclusivearch 标签;


--The exclusivearch Tag  --独有的,排外的架构的标签(其实顾名思义很好理解)
这个标签告知RPM只能在指定的架构上构建软件包。为什么这么做?这个标签会确保没有其他平台架构将错误的构建。
----------------------------------
ExclusiveArch: sparc alpha           
-----------------------------------
在这例子中的包只能在指定的架构上那个构建;如果你还是想不在某个平台平台架构上构建,可以使用 excludearch 标签;


--The excludeos Tag --排除os的标签
用来排除指定的操作系统。ExcludeOS: linux irix


--The exclusiveos Tag  --指定os的标签
和上面 excludeos的意思相反;只在指定的os上构建;


*******Directory-related Tags 目录有关的tags
--The prefix Tag
这个标签可以指定安装时的路径,而这个指定需要在files标签中也做对应的改动:
Prefix: /opt
在files中的改动:
/opt/blather/foonly


---The buildroot Tag 构建根目录
顾名思义用于制定一个构建根目录。这名字可能会误导你,实际是作为软件包在构建过程的install使用。
这里只是简单的说明,详细的描述会在后面说明。
比如说:
----------------------------
BuildRoot: /tmp/cdplayer
-------------------------------
buildroot 标签可以在构建过程中被命令选项"--buildroot" 指定的路径覆盖。


****Source and Patch Tags 源码饿补丁有关的标签
要构建并打包软件,RPM必须知道源码是谁。如何实现这一目的呢!使用一系列sources 标签来通知RPM源码
的信息和补丁的信息。


--The source Tag 源标签
源标签是一个spec文件的核心。虽然你只看到了一个描述的数据,但实际上他执行了两个功能:
<1>显示软件开发者可用的源文件;
<2>告诉RPM源码的名称;
--虽然没有硬性规定对于第一个功能,但是一般认为是"URL";URL指向源文件。源文件必须是路径的最后一个元素;
看一个例子:
Source: ftp://ftp.gnomovision.com/pub/cdplayer-1.0.tgz  
有了这一行,RPM将会在源文件(SOURCES目录)中寻找cdplayer-1.0.tgz 这个文件。
--一个spec文件可能会包含不止一个源标签。这就需要源标签必须具备唯一性以便于识别,我们在原标签的尾部加上数字
来表示不同的多个源文件。要注意的一点是Source在spec文件表示Source0,看下面:
Source: blather-4.5.tar.gz   #不加数字结尾默认会为0
Source1: bother-1.2.tar.gz
--------------------------------
Source0: blather-4.5.tar.gz
Source1: bother-1.2.tar.gz
套用老外的一句话:Either approach may be used. The choice is yours. ---条条大路通罗马,看你的选择!!


--The nosource Tag 
这个标签可以用在省略一个或者多个源码包的时候。为什么要省略,神呐!!为甚有人会去找源文件的麻烦,只有排除它吗?
答案是:也许吧!这样,我们来看一个例子:相信你听说过一个PGP这个软件吧!PGP包含加密程序,美国政府限制出口。
而刚好创建一个PGP包文件,由此产生的包不能合法的美国和其他国家之间的传播,反之亦然。
--然而所有除了源码的其他文件都是用RPM打包吗?这样理解,一个二进制文件有没有PGP作用不大,但是对于一个源码包而言呢?
它将包含规范文件,也许一些补丁,甚至一个图标文件。因为有争议的PGP软件不是一个源码包的一部分,这个净化源包可以在任何国家合法下载
下载一个副本的人可以合法获得PGP来源本身,将它们在RPM的源目录,并创建一个二进制包。他们甚至不需要改变nosource标记。
一个rpmbuild -ba 命令后,用户会完全使用PGP二进制包文件。
这个东西是美国人搞得一个安全的东西,但是对谁来说是安全的我们不得而知????建议可以使用开源的GPG(Gnu Privacy Guard)
--说了这么多,看看怎么使用:
--------------------------------------------------
nosource: <src-num>, <src-num>…<src-num>
source: blather-4.5.tar.gz
Source1: bother-1.2.tar.gz
source2: blather-lib-4.5.tar.gz
source3: bother-lib-1.2.tar.gz
----------------------------------------------------
如果blather bother-lib不要被打包,下面的写法就ok!!
------------------------------------------------
NoSource: 0, 3
--------------------------------------------------
这里的数字0指的是什么还记得吧,spec文件中第一个未编号的源会被RPM自动编号为0;


---The patch Tag  补丁标签
补丁标签用于识别哪一个补丁将被打包进软件包。补丁文件也存在于SOURCES目录下.
Patch: cdp-0.33-fsstnd.patch
补丁文件的命名没有什么硬性的要求,但是依照惯例名字应该是以软件名和版本开始并用破折号‘-’隔开,
补丁文件名称的下一部分通常包括一个或多个词表明补丁的原因。


--一个spec文件可能包含不止一个补丁文件,补丁标签的命名和Source标签类似;
-----------------------------------------------------------------------
Patch: blather-4.5-bugfix.patch
Patch1: blather-4.5-config.patch
Patch2: blather-4.5-somethingelse.patch
或者, 少了多了一个0编号!!
Patch0: blather-4.5-bugfix.patch
Patch1: blather-4.5-config.patch
Patch2: blather-4.5-somethingelse.patch
------------------------------------------------------------------------


The nopatch Tag
--和nosource 类似
------------------------------
NoPatch: 2 3
-----------------------------


*****************Scripts: RPM's Workhorse 做苦力的脚本:*****************
RPM 用脚本来控制构建的过程是spec文件中变幻多样并精彩的的一部分。大多数spec文件也使用脚本来来实行各种
任务,包的安装和卸载;
--每一个脚本的开始用一个关键字。比如,关键字%build 标志着RPM开始执行软件包打包过程中的编译阶段。
值得注意的是,严格的来说这些是spec文件的一部分而不是脚本。比如说,他们不是以调用shell开始执行。而是将脚本各部分
放在一个文件中由RPM来作为一个完整的脚本来执行。这就是RPM 强大的一种体现:任何脚本都可以由RPM来执行。
--我们一起来看看在build过程中脚本的使用;
---Build-time Scripts 编译时脚本
每个软件开发人员都知晓RPM在打包的build阶段执行脚本的步骤:
解压源文件---编译软件----安装软件(install阶段呢)---clean一些临时文件。
尽管每个脚本执行特定的功能,但是它们在一个共同的环境中。rpmbuild的一个参数--test已经在新版本中找不到了,否则我们可以一睹
RPM根据spec文件创建的每个阶段的脚本。????????
所以这里我就不分析了》??????????我觉得这个参数选项很有用但不知道为什么取消???
--好了先不管这么多,反正这些build时的脚本时会创建的,而且确实从在,我们可以通过其他方式获得这些脚本!!!自己想想》》


当你执行了rpmbuild -b{a/p/i/c}  cdplayer-1.0-1.spec 命令中任意个参数选项时,我们可以看到:
--------------------------------------------------------------
构建目标平台:mips64el
3252 为目标mips64el构建
3253 执行(%prep): /bin/sh -e /var/tmp/rpm-tmp.zXjuSe
3254 + umask 022
3255 + cd /home/zhongtian/rpmbuild/BUILD
3256 + patch_command='patch -p1 -F1 -s'
3257 + cd /home/zhongtian/rpmbuild/BUILD
--------------------------------------------------------------
你不用管我使用的平台,关键看‘/var/tmp/rpm-tmp.zXjuSe’ --这个脚本就是RPM为prep阶段生成的脚本,而且是以临时脚本的
形式存在。构造完整之后会被清除。在这一过过程中会这只一些列的环境变量。简要来说如下所示:
-------------------------------------------
RPM_SOURCE_DIR 
RPM_BUILD_DIR
RPM_DOC_DIR 
RPM_OPT_FLAGS 
RPM_ARCH
RPM_OS
RPM_BUILD_ROOT
RPM_PACKAGE_NAME
RPM_PACKAGE_VERSION 
RPM_PACKAGE_RELEASE 
-----------------------------------------------
上面所列举的这些变量是由RPM的全局宏配置文件中定义的,旧版本上在/etc/rpm/macros这个文件中,用户配置文件可以在
家目录下配置“per-user configuration should be added to ~/.rpmmacros” ,这句话解释的很清楚了。在新版本的RPM中
默认的全局宏配置文件路径改变到/usr/lib/rpm/macros中。
来看看:
------------------------------------------------------------------
%___build_pre   \
  RPM_SOURCE_DIR=\"%{u2p:%{_sourcedir}}\"\
  RPM_BUILD_DIR=\"%{u2p:%{_builddir}}\"\
  RPM_OPT_FLAGS=\"%{optflags}\"\
  RPM_LD_FLAGS=\"%{?__global_ldflags}\"\
  RPM_ARCH=\"%{_arch}\"\
  RPM_OS=\"%{_os}\"\
  export RPM_SOURCE_DIR RPM_BUILD_DIR RPM_OPT_FLAGS RPM_LD_FLAGS RPM_ARCH RPM_OS\
  RPM_DOC_DIR=\"%{_docdir}\"\
  export RPM_DOC_DIR\
  RPM_PACKAGE_NAME=\"%{name}\"\
  RPM_PACKAGE_VERSION=\"%{version}\"\
  RPM_PACKAGE_RELEASE=\"%{release}\"\
  export RPM_PACKAGE_NAME RPM_PACKAGE_VERSION RPM_PACKAGE_RELEASE\
  LANG=C\
  export LANG\
  unset CDPATH DISPLAY ||:\
  %{?buildroot:RPM_BUILD_ROOT=\"%{u2p:%{buildroot}}\"
------------------------------------------------------------------
在全局宏配置文件中定义了这些宏的属性,以及宏扩展之后的具体信息,来看:
----------------------------------------------------------------------------
#       The directory where sources/patches from a source package will be
#       installed. This is also where sources/patches are found when building.
#       源码文件和补丁文件等打包所需的源文件在目录路径
%_sourcedir             %{_topdir}/SOURCES


#       The directory where the spec file from a source package will be
#       installed.
%_specdir               %{_topdir}/SPECS


#       The directory where newly built source packages will be written.
%_srcrpmdir             %{_topdir}/SRPMS


#       The directory where buildroots will be created.
%_buildrootdir          %{_topdir}/BUILDROOT


#       Build root path, where %install installs the package during build.
%buildroot              %{_buildrootdir}/%{name}-%{version}-%{release}.%{_arch}


#       Directory where temporaray files can be created.
%_tmppath               %{_var}/tmp


#       Path to top of build area.
%_topdir                %{getenv:HOME}/rpmbuild


#       The path to the unzip executable (legacy, use %{__unzip} instead).
%_unzipbin              %{__unzip}
----------------------------------------------------------------------------
上面这些宏的扩展后的原型在全局宏的配置文件中有详细的定义,我这里列出了常见的几个,具体可以在这文件中查看;


--脚本还设置一个选项,让shell打印每个命令,完成宏参数的扩展。最后,设置默认的权限。经过这个节点之后,脚本开始发生变化。
让我们一起看看RPM执行的脚本的顺序。


----The %prep Script 
The %prep Script 这个脚本是RPM在包的构建过程中首先执行的脚本。
在%prep脚本之前,RPM已经初步的进行了一致性检查,如规范文件的源标签指向文件是否实际存在。首先%prep脚本的内容控制RPM切换目录
到构建域(这里的域是指工作所在的目录),默认这个路径在家目录下的rpmbuild/BUILD/ 目录中(老版本在 /usr/src/redhat/BUILD)。
--在这一点,%prep 脚本负责下面几件事情:
**创建构建过程所需的顶层目录。
**把源码解包到构建时目录BUILD中。
**如果有patch的话打上补丁。
**执行其他必要的动作让源来处于准备构建的状态,为下一步构建过程做准备。
--上面列出的前三条动作在大多数软件包的打包过程中比较常见。正因为如此,RPM提供了两个宏使这一过程大为简化。这两个宏的具体描述
在下面的《Helpful Shorthand for Package Builders》部分具体讲述。
--上面的最后一条包括创建一些目录或者其他必要的让源处于准备构建的状态。总之,%prep脚本可以是一行只包含
%setup宏的形式,亦或是多行诡异的shell程序!(翻译成“诡异”好吗?)


----The %build Script
--其实这系列的操作你可以理解为“接力赛模式”,%build 脚本捡起%prep的遗志继续拼搏,来完成下一阶段的构建任务。那么,%build 是否
可以一统江湖吗?我们再往下走!!一旦%prep脚本为构建的过程做好准备,但是%build脚本给人感觉有一点虎头蛇尾,正常情况下
调用make,后者一个配置脚本或什么都没有。


--和前面的%prep脚本类似,%build脚本有同样的环境变量来使用。如%prep, %build也会切换目录到软件的包顶层构建目录中去,
具体目录宏是RPM_BUILD_DIR(通常被命名为 <name>-<version> 前面这种格式),下面我把这宏观的具体扩展列了出来:
------------------------------------------------------------------------------------------------------------------
RPM_BUILD_DIR=\"%{u2p:%{_builddir}}\"\


#       The directory where sources/patches will be unpacked and built.  源码和补丁会在这个目录中解包并编译。
%_builddir              %{_topdir}/BUILD
-------------------------------------------------------------------------------------------------------------------


--和%prep不同的是,%build阶段的脚本没有那么多可用的宏来被脚本使用。原因当然很简单:因为我们都知道有个make命令来帮忙,
或者这么理解,这一阶段主要编译源码,而在稍大一点的工程的构建过程还没有那个宏能胜任。


----The %install Script   
--install脚本的执行环境和其他脚本一样,还是切换工作目录到构建的顶层目录中去。
--顾名思义,%install 阶段的脚本负责新build的软件的install(这里会解释一下什么叫安装,虽然比较基础。)。多数情况下,
这里就是一个make install命令,或者是拷贝文件以及创建目录。
####安装实际的过程就是将编译好的二进制类型的软件包放在指定的目录下,我们平时安装软件就是这样的过程。
--需要区分的是这里的install是‘虚安装’,我们这里的目的是打包软件,打包好的软件里包含了已经编译好的二进制程序,当用户
安装的我们打好的包的时候,这些二进制软件包会被拷贝到安装程序中指定的目录下
来看:(我们构建过程中的安装目录是:{_topdir}/BUILDROOT/%{name}-%{version}-%{release} 前面我们讨论过,还记得吗)。


---The %check Script  检查脚本,
检查%check本身是包构建的一个阶段的,只不过这阶段不太长用。这个脚本和其他脚本类似,他的要务是对编译的软件进行测试。典型
的例子是make test 或者make check。
##注意:RPM在4.2以后的版本支持这个功能。


---The %clean Script
还是,顾名思义,%clean脚本用来清理软件的构建目录树。RPM默认会帮你做清理工作,
但是在某些情况下(当你使用--buildroot参数指定安装的目录的时)你需要包含你的%clean脚本。
--大多数情况下你只需要一句简单的命令:
----------------------------------------------------
rm -rf $RPM_BUILD_ROOT
----------------------------------------------------
哈哈!!所以前面说"--buildroot" 参数可能会咬你一口!!


****Install/Erase-time Scripts  安装或者卸载时的脚本(真实安装)
下面这几类的脚本在spec文件中主要被用于软件的安装或者卸载。在整个软件包的生存周期里
有四个脚本在不同的时期被执行。如下:
**安装之前
**安装之后
**卸载之前
**卸载之后
--与前面讨论的构建时的脚本不同的是,在这种情况下没有对这些脚本的环境变量。
唯一可用的环境变量就是RPM_INSTALL_PREFIX ,而这还只是对安装只使用唯一的安装前缀的情况。
--和构建时脚本不同的是,这会定义一个参数。这个唯一的参数是一个数字,这数字代表当前系统安装的这个软件包的数量。听起来
有点抽象,我们下面看一个例子:
--假设一个包名为blather-1.0的软件被安装了且没有旧版本的blather被安装。因为在软件安装的过程中有两个
脚本%pre和%post被执行,在此期间参数1被传递给这个脚本,因为软件blather安装的数量是1.
--继续深入这个例子。当一个新版本的blather软件包,版本是1.3的已经可用了。那么显然已经是升级的时间了。那么在
升级的过程中会是怎样的一个脚本的值呢?一旦新版本blather-1.3被安装,脚本%pre和%post的参数值会在之前的版本的
基础上加1变为2 。在升级的最后阶段会将blather-1.0卸载。而在包的卸载过程中,脚本 %preun and %postun 会被执行
来卸载旧版的软件。至此,系统上将只有一个新版本的blather-1.3被安装。
--在这例子的最后,我们决定也卸载掉新版本(version 1.3)。我们不需要其他什么东西,只要这个包被卸载,那么
脚本 %preun and %postun 依旧会被执行。一旦软件blather完全被卸载,那么传给脚本的参数就是0。


--综上所述,可能使用的参数是什么?嗯,它有两个非常有趣的特点:
<1>当软件包的第一个版本被安装,传给 %pre and %post脚本的参数是1;
<2>当软件包的最后一个版本被卸载,传给 %preun and %postun脚本的参数是0;
基于这些特性,很容易编写一个脚本安装时,在特定的情况下可以采取某些行动。
通常,参数被用于%preun或%postun脚本执行指定的任务当最后后一个包被卸载时。要注意的就是软件包的名字在不同系统
环境上差异的问题。除非你能确保不同系统使用的脚本的一致性。


----The %pre Script
这个脚本在软件包安装之前被执行。这种安装前需要执行某些脚本的软件包比较少见。350个包组成的Red Hat Linux Linux 4.0利用它。
???????????


----The %post Script
这个脚本在已经安装过的软件包安装时使用。主要的原因是在新版本的包被安装后用ldconfig来更新可用的共享库!当然,还有其他的
功能可以被%post脚本执行。比如:使用%post脚本添加shell的名称为/etc/shells在安装一个shell包的时候。
--如果一个包使用%post脚本来执行某个功能,常常还会包含一个%postun 脚本来执行相反的功能在包被卸载时。


---The %preun Script  
在用户卸载你的包之前查看它时,你可以在%preun脚本中做这些事情。也就是说,在立即卸载软件包之前所要
做的动作都可以在这里来处理。


---The %postun Script
这个脚本在包被卸载后执行(你可能会问都卸载了,怎么还需要处理啊??)这就是最后一步的清理工作。通常,
这个脚本用来运行ldconfig来从/etc/ld.so.cache 中移除相关的'.so' 库文件。


----Verification-Time Script — The %verifyscript Script
 %verifyscript脚本当RPM执行检查命令的时候被执行。




 
========
说明
Notes
==============
[1]
Described in the Section called --test — Create, Save Build Scripts For Review in Chapter 12.


[2]
One popular hack to make spec files containing the %check script "work" with RPM versions older than 4.2 roughly similarly as in newer versions is to include it immediately after the %install script in the spec file and append "|| :" to it, like:


%check || :
                
[3]
Keep in mind that this command in a %clean script can wreak havoc if used with a build root of, say, /. the Section called Using --buildroot Can Bite You! in Chapter 12 discusses this in more detail.


[4]
Or it will be 1, once the package is completely installed. Remember, the number is based on the number of packages installed after the current package's install or erase has completed.












=====================================
=================================================


Macros: Helpful Shorthand for Package Builders
宏:让生活更简单


--RPM从某种意义上不支持的一系列专有命令被定义为宏,这种方式可以通过一个宏名而被简单地引用。
--然而,在包的构建过程中有两个非常恒定不变的部分就是解包(unpack)和打补丁(patching)。正因为这两个过程
在大部分包的构建中基本保持不变,所以RPM为了简单起见提供下面两个宏来完成这项任务。
<1>%setup 宏,用于将源码解包。
<2>%patch 宏,用来给源码打补丁(如果需要的话)。
这两个宏的使用包含在%prep阶段的脚本当中。其他地方一般不会使用。当然这两个宏的使用不是强制的,你也可以写一个
%prep阶段的脚本而不是用这两个宏。但是在大多数的情况下宏还是会让你的生活更简单。


---The %setup Macro 
如上所述,%setup 宏,用于将源码解包为编译做准备。一般情况下,这个宏的使用无需什么选项参数,从spec文件中的source 标签中取出
源对象的名称。下面看一个例子,例子的源标签指定了源名称。
-----------------------------------------------------------
Source: ftp://ftp.gnomovision.com/pub/cdplayer/cdplayer-1.0.tgz
------------------------------------------------------------
下面是%prep脚本的内容:
----------------------------------------
%prep
%setup
---------------------------------------------
--在这个简单的例子中,%setup 宏会扩展为下面的命令:
----------------------------------------------------------------------
cd /usr/src/redhat/BUILD   在新版本的RPM中此目录的改变在前面以讨论过
rm -rf cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
----------------------------------------------------------------------
--我们可以看到,%setup宏将切换目录并删除之前的构建树。接下来使用gzip程序解压源文件(源文件的名称信息来自于source标签),并使用管道
把解压完的文件传个tar程序来解包(解压和解包是两个过程,不要混淆)。在来测试解包的返回值是否为0(如有不清楚可以了解shell的相关返回值检测的内容)。
如果成功(即返回值为0),宏继续下一步操作。
--到这一步,源文件的解包已经完成。我么看到%setup宏继续切换目录到构建顶层目下的cdplayer目录中。这两个cd命令也是%setup宏的扩展。最后%setup宏使用chown
和chmod命令改变构建目录下文件的属主和权限,到此为止。
--但是,这里%setup宏只是在简单的构建的情况下才这么使用,在较复杂的构建实例中我们可以采用一些参数来控制这个过程。下面来看:
----%setup宏的参数:


******  -n <name> — Set Name of Build Directory  


在上面的例子中,setup宏只是做了一些简单的动作,而且在上面的例子中,源文件的名称是在之前创建好并和tar包的文件名称相同,使用的格式为<name>-<version>这种格式。
然而不是所有的情况都如此理想。有些情况下,tar包的文件名和源文件名不一样,不都像上面的‘名称+版本’的这种格式。但是没关系,在这种情形下我们可以使用
%setup宏的'-n' 参数选项。下面来看一个这样的例子:
--我们假设,在解包之前已经创建了cdplayer目录;
-------------------------------------------
%setup -n cd-player
--------------------------------------------
--这回我们看到最终的命令为:
--------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cd-player
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cd-player
cd /usr/src/redhat/BUILD/cd-player
chown -R root.root .
chmod -R a+rX,g-w,o-w .
----------------------------------------------------
--这里的最终命令和前面没有加‘-n’参数选项时候除了rm -rf和cd命令的对象变为cd-player而不是cdplayer-1.0 有差别之外没别的区别。
--这说明在后面的一系列构建过程中所有目录切换的目标都变为'-n'参数指定的名称。多个源标签的的实例在后面有专门的介绍。
需要注意的是:如果使用‘-n’参数指定的名称与解包之后的名录名称不匹配,构建过程将立即停止,所以使用的时候要注意这里。




******  -c — Create Directory (and change to it) Before Unpacking
--如果你运气够好的话,我肯定你用tar解包的某个瞬间过后你的当前目录被解开的文件的充斥的玲琅满目苦不堪言!有时候源文件创建的时候没有
顶层目录(当然这样是不专业的,我们不希望这么做)。
--到目前为的示例中,我们看到%setup‘期望’或者说‘预计’归档建立自己的顶级目录。。如果不是这样,你可以使用‘-c’选项来帮助你。
在这里‘-c’选项创建并切换到目录中去在解包源码归档文件之前。来看看情况:
-----------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
mkdir -p cdplayer-1.0
cd cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
------------------------------------------------------------
可以看到与没有参数不同的是在解包源码之前多了一个mkdir和cd命令。当然你也可以同时使用这两个参数 %setup -c -n blather。


*****  -D — Do Not Delete Directory Before Unpacking Sources
当%setup宏配合使用'-D'参数可以阻止%setup宏删除软件的顶层目录。这个参数可以使用在当源文件解包后就已经存在目录树的情况下。
来看看使用'-D'参数之后的有什么变化:
---------------------------------------------
cd /usr/src/redhat/BUILD
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
----------------------------------------------
这如前面所述在tar命令之前的rm命令‘去了’!!!


****** -T — Do Not Perform Default Archive Unpacking
这个‘-T’选项禁用了%setup宏正常从源标签编号为0开始解包源文件的操作。下面是使用‘-T’之后的结果:
--------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
---------------------------------------------------------
没有解压和解包的过程出现,这个选项看着是没有多大意义的,你会不会觉得这种方式不可思议。后面我们会看一个
这样的例子。


*****  -b <n> — Unpack The nth Sources Before Changing Directory
--这个‘-b’选项一般和源标签(source:)结合来使用。具体来说,它是确定在spec文件中那些源标签编号所指的
文件会被解开。
--这个‘-b’选项需要一个数字参数来匹配已存在的源标签(source tag)。如果不提供数字参数给%setup宏的‘-b’选项
的话就会出现构建终止。
----------------------------------
# rpmbuild -ba cdplayer-1.0.spec
* Package: cdplayer
Need arg to %setup -b
Build failed.
#
----------------------------------
还记得第一个源标签的编号默认为0吧!我们把%setup宏这一行写为 ‘ %setup -b 0: ’ 之后我们看看会发生什么事情:
-------------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
--------------------------------------------------------------------
奇怪的是,源被连续两次解开。其实单单在这里讲没有什么实际意义,不过当你意识到前面所说的‘-T’选项
的作用的时,你是不是发现什么了呢!!因为前面‘-T’禁用了默认的解开文件从源标签0处,这里‘-b’选项
选择了一个指定的源文件且源标签标号为0所以这两次的恰巧想”想到一块去了“,下面改写为:
-------------------------------------
%setup -T -b 0
-------------------------------------
再来看命令结果,我们发现:
--------------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
--------------------------------------------------------------------
本该如此!!继续看下一个选项。


******  -a <n> — Unpack The nth Sources After Changing Directory
这个‘-a’选项和‘-b’选项比较相似,除了先切换目录然后在解开源文件这里有些不同。就像‘-b’选项一样
‘-a’选项也需要‘-T’选项,目的是阻止两次的解开文件的命令。下面看看 %setup -T -a 0 的结果:
--------------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
cd cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
--------------------------------------------------------------------
你也注意到了,这里没有mkdir命令创建顶层目录树直接cd了。基于上面的例子再加入‘-c’选项才算是严格:
------------------------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
mkdir -p cdplayer-1.0
cd cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/cdplayer-1.0.tgz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
-------------------------------------------------------------------------------
这种情况可以用在解开源文件之后没有顶层目录的时候。


-----Using %setup in a Multi-source Spec File
如果所有这些相互关联的选项都被用来对付单个源文件的解压和解包的话,似乎有点”炮打麻雀的意思“。
--没错儿,这么多选的真正原因是为了使多个单独的源文件的结合能够变的更简单。看看这种多源文件的处理:


--对于本示例来说,我们的spec文件中有下面撒个源标签(source tags):
--------------------------
source: source-zero.tar.gz
source1: source-one.tar.gz
source2: source-two.tar.gz
---------------------------
当然解开第一个源文件是不费吹灰之力的;需要做的及时一个%setup宏不带任何参数(%setup):
---------------------------
%setup
---------------------------
他将产生下面的命令序列:
----------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/source-zero.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
-------------------------------------------
如果source-zero.tar.gz没有包含顶层目录我们也只需要一个‘-c’选项:
--------------
%setup -c
----------------
结果就会变为:
-------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
mkdir -p cdplayer-1.0
cd cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/source-zero.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
-------------------------------------------------------------
当然,如果顶层目录名称和包名不匹配,也只需要再加上选项‘-n’:
--------------------------------
%setup -n blather
--------------------------------
结果就会变为:
----------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf blather
gzip -dc /usr/src/redhat/SOURCES/source-zero.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd blather
cd /usr/src/redhat/BUILD/blather
chown -R root.root .
chmod -R a+rX,g-w,o-w .
----------------------------------------------------------------
或者直接:
-------------------------
%setup -c -n blather
-------------------------
结果就是:
----------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf blather
mkdir -p blather
cd blather
gzip -dc /usr/src/redhat/SOURCES/source-zero.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd /usr/src/redhat/BUILD/blather
chown -R root.root .
chmod -R a+rX,g-w,o-w .
----------------------------------------------------------------
上面我们分析了几种情况下的操作,下面我们来看如何添加第二个源文件。
我发现事情变得越来越有意思了!!!!
-----首先,我们需要识别源标签(也就是代表那个源文件)是哪个。所以我们就需要使用
选项‘-a’或者‘-b’ 根据源文件的特点(解开之后是否包含顶层目录)。这个示例我们先来说说
选项‘-a’。添加选项并给参数为1表示指定源文件为编号为source1 标签。来看:
------------------------
%setup -a 1
------------------------
因为我们已经在前面看到使用‘-a’或‘-b’选项导致解开文件时的二重性,我们需要添加选项‘-T’禁用默认
解开源文件的操作。
------------------------
%setup -T -a 1
--------------------------
接下来,为了保证顶层目录没有被删除。如果不这样做,我们第一个解开的源文件就会被删除。这就意味着我们需要包含
选项‘-D’来阻止这种情况的发生。添加完最后一个选项,
------------------------
%setup
%setup -T -D -a 1
--------------------------
现在我们看看下面的命令:
--------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/source-zero.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
cd /usr/src/redhat/BUILD
cd cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/source-one.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
-----------------------------------------------------------------
--到目前为止,一切顺利!!让我们来把最后一个源文件包含进来,但是,对于这个文件,我们需要将其
解开到顶层目录cdplayer-1.0下的一个名为database的子目录中。想想这里还能使用%setup宏么??
--这就要论情况而定了,如果source-two.tgz自动创建子目录database的话一切好说。如果不是,我们就需要手动
来添加。在我们的示例中我们来讨论一个source-two.tgz不会创建子目录的情况。所以说,接下来我们需要靠自己来
手动搞一个子目录并切换到此子目录中。下面是我们手工添加的%prep脚本部分:
--------------------------------------------------------------------------------
%setup
%setup -T -D -a 1
mkdir database
cd database
gzip -dc /usr/src/redhat/SOURCES/source-two.tar.gz | tar -xvvf -
--------------------------------------------------------------------------------
这部分脚本的结果:
-----------------------------------------------------------------
cd /usr/src/redhat/BUILD
rm -rf cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/source-zero.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
cd cdplayer-1.0
cd /usr/src/redhat/BUILD/cdplayer-1.0
chown -R root.root .
chmod -R a+rX,g-w,o-w .
cd /usr/src/redhat/BUILD
cd cdplayer-1.0
gzip -dc /usr/src/redhat/SOURCES/source-one.tar.gz | tar -xvvf -
if [ $? -ne 0 ]; then
  exit $?
fi
mkdir database
cd database
gzip -dc /usr/src/redhat/SOURCES/source-two.tar.gz | tar -xvvf -
-----------------------------------------------------------------
--这三个命令我们添加在%prep脚本部分的最后。你应该大胆的尝试的去修改%setup宏部分
来做你想做的事情,不要怕!!
--说了这么多,都快要把RPM的第二个宏给冷落了!!下面我们赶紧来看宏%patch。


----The %patch Macro
补丁宏(%patch),顾名思义,是用来应用补丁的。在下面我们的示例中,spec文件有下面三个patch 标签:
------------------------------------
patch0: patch-zero
patch1: patch-one
patch2: patch-two
------------------------------------
很简单,%patch宏可以在没有选项时使用。
-----------
%patch
-----------
产生下面的命令:
---------------------------------------------------
echo "Patch #0:"
patch -p0  -s < /usr/src/redhat/SOURCES/patch-zero
---------------------------------------------------
--宏%patch会很好的显示一条消息来表示一个patch正在被应用,然后调用patch命令去完成这件差事!!这里有两个
选项可以给patch命令使用:
<1>选项‘-p’ 可以驱使patch命令移除指定数目的斜杠(任何干预目录)从前面的指定的文件名中在patch中。在这种情况下,没有什么被移除的。
<2>选项‘-s’ 可以驱使patch命令去应用补丁而不显示任何信息,只有发生错误会被显示。
那么%patch宏是如何知道应用那个patch的呢?还记得吗,就如同source 标签,每个patch标签也从0开始被编号。而%patch宏默认应用补丁的名称
是从patch(patch0)标签所在行开始的。


--- Specifying Which patch Tag to Use   指定使用哪个patch标签
这里%patch宏实际上有两种不同的方式指定使用那个patch标签。第一种方式就是直接将你要应用的patch标签的编号数字跟在%patch宏后面。比如说,
为了应用patch2标签指定的行,可以按照下面的%patch宏来应用:
------------------------------
%patch2
------------------------------
还有另外一种方式就是使用选项‘-P’(大写)。这个选项紧跟其后的是你所希望应用的patch标签的编号。所以说下面这一行和上面一行的功能是一样的:
-------------------------------
%patch -P 2
-------------------------------
当心,‘-P’选项将不会默认应用patch0.也就是说如果你选择使用‘-P’选项应用指定编号的补丁,你必须按照下面的方式当你想要应用编号为0的补丁时:
-----------------------------
%patch -P 0
------------------------------


*****:  -p <#> — Strip <#> leading slashes and directories from patch filenames
小写的‘-p’选项直接发送给patch命令。‘-p’选项后面跟一个数字,表明指定数量的正斜杠(斜杠之间的目录)被剥离从当前补丁文件。关于选项的更多信息
可以查看patch的man手册,这里面有非常详细的描述。


*****:  -b <name> — Set the backup file extension to <name>
当使用patch命令应用一个补丁,
。................
.................
..........................


*******:   -E — Remove Empty Output Files


因为这里我还没有实操,这里的东西我会在后来的学习中补上tobecon !!!






============================
====================================================
The %files List ---暂且成为文件的列表
文件列表告诉我们RPM将会把构建系统中的(这里可以简单理解为rpmbuild目录下的一系列目录和文件)哪些文件打包。每一行
包含一个文件列表,在这个文件之前可能还会存在一或多个指令。这些指令会告诉RPM关于文件的额外信息(如权限)的内容将在下面详细描述。


正常情况下,每个文件包含其全路径。这里路径有两个作用。首相,他描述了文件在构建系统中的位置。其次,他表示文件在安装时的位置【1】。


对于创建目录包含数百个文件包,它可以相当繁琐的包含每个文件创建一个列表。为了更简单的对应这种情形,如果%files 列表包含一个目录,
RPM将自动打包该目录下的每一个文件,这些目录中的子目录也一样会被打包。


【1】并不完全如此,当一个可重定位包被构建。关于可重定位包更详尽的信息请参阅--第十五章




******
****************


Directives For the %files list ----对文件列表的指令。
文件列表%files 可能包含许多不同的指令。他们被用来做下面的事情:
**标示文档类或者配置文件
**确保文件有正确的权限和属主设置。
**控制在包验证阶段那些方面的信息被检查。
**不那么乏味!!!

在文件列表%files中,一个或者多个指令可能被放在同一行,空格符隔开多个文件名。所以,如果%foo 和 %bar是两个文件列表%files指令,
他们将会被应用于文件baz如下所示:
-------------------------------------------------
%foo %bar baz
-------------------------------------------------
现在是时候来一睹栖息于文件列表%files中的指令了。


---File-related Directives   文件相关指令
RPM根据文件类型来处理不同文件。然而,RPM没有一种自动判定文件类型的方式。所以,就要包的构建者在文件列表%files中适当的标示文件一些属性。
这个动作可以使用下面的指令来完成。


需要的提醒您注意不是所有的文件都需要标示。继续阅读下面的段落,你会发现这些指令或者说指示仅仅使用在一些特殊情况下。在大多数包中,大部分文件列表中的文件将不需要被标示。


-------The %doc Directive  文档类的指令或者说指示(我觉得指示更合理一点)
这个%doc指示后面的标记的文件名就是文档。RPM会记录文档文件在自己的数据库中,这可方便用户很容易就找到安装包的的信息。另外,RPM会创建一个包指定的文档目录在安装期间并
移动文档到该目录。这个额外的步骤是否发生取决于一个指定的文件。我们看下面的例子:
--------------------------------------------------
%doc README
%doc /usr/local/foonly/README
--------------------------------------------------
这个README文件存在于软件构建时的顶层目录下,将被包含在包中。当包被安装时。RPM创建在文档目录下创建一个名为包名的目录(比如,<software>-<version>-<release>),并拷贝README
到其中。新创建的目录和README文件将被作为文档标记在RPM的数据库中。这里默认的文档目录是/usr/share/doc/,也可以改变这个默认目录通过设置defaultdocdir宏在RPM的配置文件中。在较新一点的版本中,此文件的定义
在RPM全局配置文件/usr/lib/rpm/macros或者/usr/lib/rpm/platform/mips64el-linux/macros 中,具体的操作看您的需求。关于更多信息,你可以阅读【Appendix B】。


文件 /usr/local/foonly/README在包构建的时候被安装进这个目录中并包含在包中。当包被安装时这个文件会被copy进入到/usr/local/foonly/目录并在RPM的数据库中标记。


--------The %config Directive  配置指示
这个%config 指示用于标记指定文件是一个配置文件。RPM会对配置文件执行额外的处理当包被移除、安装或升级时。这是因为配置文件的性质决定:主要是因为配置文件可能经常由系统管理员改动,并且这些改动不应该丢失。


这里对%config有一个限制就是其后面不能跟多个文件名。按照下面的方式来指定配置文件是一种合理的方式。
-------------------------
%config /etc/foonly
-------------------------
温馨提示:这理得路径是指全路径,因为在构建的安装阶段是需要的。


---------The %attr Directive  暂时理解为属性指示
这里%attr 指示允许通过文件的三个关键属性来更细致的控制。
<1>文件权限或者说模式(chmod控制的三个属性)
<2>文件的用户ID
<3>文件的组ID
这里的%attr指示可以按照以下格式:
---------------------------------------
%attr(<mode>, <user>, <group>) file
---------------------------------------
解释:mode可以使用传统的数字格式来指定,user和group可以使用字符串来指定,比如说"root".我看下面一个简单的%attr示例:
---------------------------------------
%attr(755, root, root) foo.bar
---------------------------------------
这里将 foo.bar 的权限改为755,属主为root用户,root组。如果其中某个属性不需要指定(通常因为这个样设置这个属性对安装来说比较合适),这里可以使用破折号"-"来代替。
---------------------------
%attr(755, -, root) foo.bar
-----------------------------
使用%attr的主要原因是允许用户在非root用户环境下可以构建包。关于这一指示%attr的更深入详细的讨论在--第十六章


---------The %defattr Directive  more属性指示
这一属性可以让我们设置默认属性,他的格式和上面的%attr类似。:
<1>文件默认权限或者说模式(chmod控制的三个属性)
<2>文件的默认用户ID
<3>文件的默认组ID
这里的%defattr指示可以按照以下格式:
---------------------------------------------------
%defattr(<file mode>, <user>, <group>, <dir mode>)
---------------------------------------------------
另外,目录模式(dir mode)可能被忽略。%defattr 多数情况在%files的顶部使用,我们在有些情况下%attr这个指示不太常用。


---------The %ghost Directive  可以翻译为”幽灵“指示吗!!!有点吓人(⊙o⊙)哦@@@
前面我们在%files中注意到,如果一个文件在文件列表%files中指定,这个文件将会被自动的包含进包中去。但是有时候一个文件虽然属于一个包,基于某些原因不想被安装--比如一些log
和state文件。
这种情况下可以使用%ghost指示来达成你的愿望。这个%ghost指示所在行的文件,RPM通过分析知道这是一个”幽灵“文件,将不会被添加进包中。然而任然需要在构建目录buildroot中需要。
下面有一个例子,这包blather-1.0的logs文件/var/log/blather.log 是默认配置。在spec文件中/var/log/blather.log包含在文件列表%files中。我们可知blather.log属于这个包。
-----------------------------------------------------------------
%install
touch $RPM_BUILD_ROOT%{_localstatedir}/log/blather.log

%files

%ghost %{_localstatedir}/log/blather.log

# rpm -qf /var/log/blather.log
blather-1.0-1
# rpm -ql blather | grep blather.log


# rpm -e blather && ls /var/log/blather.log
ls: /var/log/blather.log: No such file or directory
-----------------------------------------------------------------
这个文件在%install阶段创建将不会被安装到/var/log/blather.log 尽管者会被添加到RPM数据库中。我们可以查找这个文件,然而他没有在包列表中出现,但是他属于这个包并且
在这个包卸载的时候也会被移除。另外也可以使用setperms参数去修改%ghost的权限。
------------------------------------------------------------------
# ls -al /var/log/blather.log
-rw-r--r--    1 root     root         3448 Jun 18 17:00 /var/log/blather.log
#chmod 666 /var/log/blather.log
# ls -al /var/log/blather.log
-rw-rw-rw-    1 root     root         3448 Jun 18 17:00 /var/log/blather.log
#rpm --setperms blather
# ls -al /var/log/blather.log
-rw-r--r--    1 root     root         3448 Jun 18 17:00 /var/log/blather.log
-----------------------------------------------------------------
看到上面权限发生了那些变化。


---------The %verify Directive  检查指示。
来吹嘘一把RPM!!!!
RPM的验证软件安装的完整性的能力让人映像深刻。但是有时候有点太深刻了!!毕竟,RPM可以从9个不同方面为每个文件检查验证。
这个%verify 指示能控制这些文件的属性被检查当RPM验证完成时。下面列出了检查的各个属性:
<1>owner (owner)(属主)
<2>Group (group)(属组)
<3>mode  (mode)(模式)
<4>MD5   (md5)md5校验值
<5>size  (size)大小
<6>Major Number (maj)主序列号
<7>Minor Number (min)次序列号
<8>Symbolic Link String (symlink)符号链接
<9>Modification Time (mtime) 修改时间
如何使用%verify指示呢? 看下面的例子,一个包安装设备文件。因为这个设备的属主发生了改变,所以进行RPM的verify对其属主/属组是没有意义的并且会发出错误报警。
因此,使用下面的%verify指示才是合适的:
---------------------------------------------------------------
%verify(mode md5 size maj min symlink mtime) /dev/ttyS0
---------------------------------------------------------------
我们忽略owner和group的检查,因为我们不希望RPM验证他们【1】。
然而,如果您想阻止RPM验证一个或者两个属性,您可以使用下面方式来替换。
--------------------------------------------
%verify(not owner group) /dev/ttyS0
--------------------------------------------


**********
*******************
Directory-related Directives   ----目录相关的指示
虽然这两个指令在本节中执行不同的功能,每个目录在某种意义上是关联的。让我们来一睹究竟:


--------The %docdir Directive  文档目录指示。
指示%docdir用于添加一个目录到包含文档的目录的列表中。RPM默认包含这些目录到/usr/doc, /usr/info, and /usr/man这些目录。
举个例子,如果下面一行是文件列表%files的一部分:
-------------------------------------
%docdir /usr/blather
-------------------------------------
任何文件在文件列表%files中来自/usr/blather的正常会被包含进包中,而且会自动标记为文档。这个指示在处理一个包要创建自己的文档目录并包含较大的的文件时非常方便。
我们可以在自己的spec文件中添加下面的行来试试:
-------------------------------------
%docdir /usr/blather
-------------------------------------
执行构建完成之后查看包的文件列表,显示:
----------------------------------------------------
# rpm -qlp ../RPMS/i386/blather-1.0-1.i386.rpm

#
----------------------------------------------------
稍等:什么都没有,/usr/blather 也没有!!!发生什么事情了?


问题在这里,%docdir 仅仅指示RPM标记指定的目录作为文档目录,而并没有指示RPM这个目录下的任何文件。
这样做,我们实际上需要提示RPM此目录下的文件必须打包。
一个简单的方法是在文件列表%
----------------------------------------------------
%docdir /usr/blather
/usr/blather/INSTALL
----------------------------------------------------
执行构建完成之后查看包的文件列表,显示INSTALL在包中:
----------------------------------------------------
# rpm -qlp ../RPMS/i386/blather-1.0-1.i386.rpm

/usr/blather/INSTALL
#
----------------------------------------------------
指示RPM仅仅显示文档文件,我们可以看到INSTALL 已经被标记为文档文件,即使%doc指示还未使用:
----------------------------------------------------
# rpm -qdp ../RPMS/i386/blather-1.0-1.i386.rpm

/usr/blather/INSTALL
#
----------------------------------------------------
当然,如果你嫌将每个文件添加到文件列表%files麻烦,不应该在这里花这么多功夫去为每个文件添加%doc。
这里有一个非常方便的做法就是添加到另一行到文件列表%files:
-----------------------------------------------------------
%docdir /usr/blather
/usr/blather
-----------------------------------------------------------
上面的第一行指示RPM标记任何在/usr/blather下的文件为文档类,第二行告诉RPM自动打包/usr/blather下面发现的任何文件,
这里的每一个单独的文件将会被打包并标记为文档。
-----------------------------------------------------------
# rpm -qdp ../RPMS/i386/blather-1.0-1.i386.rpm
/usr/blather
/usr/blather/COPYING
/usr/blather/INSTALL
/usr/blather/README

#
-----------------------------------------------------------
这里%docdir指示能节省相当多的功夫在文件列表创建时。唯一值得注意的是你必须保证这个目录仅仅包含你想标记为文档类的文件。
记住,与此同时,这里%docdir后表示的所有子目录也将被标记为文档目录。


-----------The %dir Directive  目录指示
如同我们在文件列表%files 中的所见,如果一个目录在文件列表中指定,这目录中的所有内容将自动被包含在包中。虽然这个特性可以很
方便(假设你可以保证这么目录下的所有文件应该被打包),但有时这确实是个问题。


解决这个问题的方式既是使用%dir指示。添加这个指示到这一行包含的的目录,RPM将只打包这个目录本身,而忽略包被创建时所在目录。光说不练假把式,
请您来看一个例子:


包blather-1.0创建目录/usr/blather作为构建的一部分。他也可能存放一些文件在这个目录。在spec文件中,目录/usr/blather包含在文件列表%files中:
-----------------------------------------------------------
%files

/usr/blather

-----------------------------------------------------------
这里在文件列表中没有其他条目作为 /usr/blather的一部分。构建完成之后我么使用RPM来查看包中的文件:
-----------------------------------------------------------
# rpm -qlp ../RPMS/i386/blather-1.0-1.i386.rpm

/usr/blather
/usr/blather/COPYING
/usr/blather/INSTALL
/usr/blather/README

#
-----------------------------------------------------------
现在文件文件/usr/blather在包构建时被自动包含,没有输入名称在文件列表中。
然而,当把文件列表中的这一行/usr/blather改为如下形式:
---------------------------------------
/usr/blather
---------------------------------------
重新rebuild软件包,包的列表文件仅仅包含/usr/blather目录;
----------------------------------------------------------
# rpm -qlp ../RPMS/i386/blather-1.0-1.i386.rpm

/usr/blather

#
----------------------------------------------------------


*******
***************************
   -f <file> — Read the %files List From <file>  -f选项,从一个文件中读取文件列表。
这个-f 选项用来指示RPM从指定文件读取文件列表。有点像spec文件中的文件列表:
----------------------------------------
%files latex -f tetex-latex-skel
/usr/bin/latex
/usr/bin/pslatex

----------------------------------------


【1】 RPM 会自动排除没有意义的文件属性验证。比如获取MD5校验从设备文件。






===================
=========================================
The Lone Directive: %package    孤独的指示(哈哈,更高级的哲人独处着,不是因为他想孤独,而是因为在他周围找不到同类...我怎么突然想起这句话呢??)
目前为止我们看到的每个指示都是在文件列表中使用,但是呢%packsge指示有所不同。他被允许用来在一个spec文件中创建多个包且可以在任何时候出现在spec文件中。
这个额外的包被称为子包。子包的命名根据起包含的内容在%package 指示后面。其格式可以表示为:
-----------------------
%package: <string>
-----------------------
这里的<string>的命名应该能描述子包的信息。这个字符串将被附加在基础报名之后产生子包名。比如,在spec文件中包含一个名称标签值为“foonly”,和一个"%package doc"行,然后子包名称就是foonly-doc。


******  -n <string> — Use <string> As the Entire Subpackage Name   使用字符<string>来作为子包的全名。
如上面看到的,子包的名称包含主包的名称。当-n 选项被添加在%package 指示之后,他会控制rpm使用后面跟的字符作为子包的全名。在上面例子中,下面的%package 行将会创建一个名为foonly-doc的子包:
---------------------------------------------
%package doc
---------------------------------------------
下面的%package行将会创建一个名为doc 的子包:
---------------------------------------------
%package -n doc
---------------------------------------------


在这里%package 指示还可以在子包构建中扮演另一个角色。此角色就是使用指定的子包作为收集标签的地方。


最后,由%package 指示指定的字符名称也可以用来表示spec文件的哪一步分是表示子包的。下面看一个例子:
-------------------------

%package -n bar

%post -n bar

-------------------------
在这个编辑工作量较大的spec文件片段,一个被称为bar的子包被定义。在后面的post-install 脚本,post-install也是子包的一部分。


子包构建的详细信息可以阅读---第十八章


===================
==================================
Conditionals    ---条件  (类似条件编译)


虽然"exclude" and "exclusive"两个标签(excludearch, exclusivearch, excludeos, and exclusiveos)提供了一些控制包是否在指定的架构或者操作系统上构建,但是仅凭这些控制还是不够精细的。


举个例子, 如果要构建一个多架构的包我们需要怎么做,只需要在%build脚本阶段做一些轻微的不同改动吗?或者说如果一个包需要一系列文件在某个操作系统下,在另一个操作系统下需要完全不同的设置吗?
我们在前面章节讨论的架构或者操作系统相关的标签面对这些情况束手无策。What can be done? 我们又能做什么呢???


一个简单的方式就是创建不同的spec文件为不同的架构或者操作系统。虽然这样做也可以,但这种方式有几个问题:
<1>较大的工作量。为一个包维护多个spec文件本身意味着为一个修改要进行多次工作,这明显增加了工作量。
<2>更容易出错。如果需要在spec文件中做较多的工作,实际上就意味着增加错误出现的几率。
另一种方式就是在某种程度上允许条件选择不同的架构或者操作系统指定的片段在spec文件中。幸运的是RPM的设计者选择了这种方式,这样可以使多平台包的构建更容易并减少出错几率。
我们将在----第十九章更深入的讨论多平台包的构建。这里,我们先撸一眼RPM的条件编译。


----------The %ifarch Conditional  架构条件
这里%ifarch 条件用于在spec文件中开始一个指定架构的的片段。这里紧随其后的是一个或多个架构说明符,每个说明符由‘逗号’或者空格分开。看个例子:
-----------------------------
%ifarch i386 sparc mips64el
------------------------------
spec文件中这一行后面的内容表示只构建Intel x86 或者 Sun SPARC-based 或者 MIPS的64位系统。然而,如果只有这一行在spec文件中,我们尝试着执行一次构建:
--------------------------------------------------------
# rpmbuild -ba cdplayer-1.0.spec
Unclosed %if
Build failed.
#
--------------------------------------------------------
这里出现的问题表示,任何条件必须使用 %else or %endif 来“closed”关闭。我们将会在本章的稍后章节回顾。


----------The %ifnarch Conditional  
和上面的%ifarch类似,只是逻辑上相反。我相信这个很好理解,就是说在spec文件中如果一个条件块由%ifarch mips64el开始,
就说构建过程中的此块只处理mips系统的构建。反之,就是除了mips之外的其他系统的构建。


%ifarch, %ifnarch 后面可以跟多个架构并且必须有%else or %endif来关闭这一条件。


----------The %ifos Conditional  
这里的%ifos用于控制RPM的spec文件处理是基于那个操系统的。格式和上面类似也可以跟多个操作系统,也需要%else or %endif来关闭条件。
--------------
%ifos linux
--------------


----------The %ifnos Conditional
和%ifos实现逻辑相反。后面跟的os将不会被处理。也需要关闭。


----------The %else Conditional 
放置的%if和%endif之间,相当于创建了两个处理块在spec文件中。其中只有一个块被执行。看个例子:
--------------------------------------------------------
%ifarch alpha
make RPM_OPT_FLAGS="$RPM_OPT_FLAGS -I ."
%else
make RPM_OPT_FLAGS="$RPM_OPT_FLAGS"
%endif
--------------------------------------------------------
当一个构建执行在Digital Alpha/AXP上,一些额外的make命令的参数被添加。其他的系统则不会添加。


------------The %endif Conditional
这里%endif用来结束spec文件中的一个条件块。它跟在每一个%if条件或者%else之后。%endif总是被条件语句所需要,否则构建将会失败。这里有一个简短的条件块,由%endif结束:
--------------------------------------------------------
%ifarch mips64el
make INTELFLAG=-DINTEL
%endif
--------------------------------------------------------
这上面这个例子中我们看到,条件块由%ifarch开始并终结于%endif。


下面我们需要对spec文件做一些更深入的了解,我们看一看RPM的一些额外的条件特性。在后面的章节,我们将探索如何为包添加依赖信息。






********************************************
*******************************************
Chapter 14. Adding Dependency Information to a Package   
第十四章  为包添加依赖信息。


自从RPM的第一个版本走向街头{(感觉有点....)---这里译为横空出世是否更恰当呢!!随便吧!!},RPM的另一方面的影响是使事情变得简单(废话)。自从RPM使得删除一个包变得如此简单,很多人就乐此不疲的开始
卸载删除包直到遇到麻烦。
偶尔被‘咬了’一口,但是和曾经遇到的很大麻烦已经被解决了。记住这些,RPM的开发者赋予RPM下面的能力。
<1>构建软件包并包含需要功能的信息。
<2>构建软件包并包含提供供能的信息。
<3>在RPM的数据库中存储提供的和需要的信息。
此外,要确保RPM能显示依赖信息,可以提醒用户如果尝试安装或者执行某些动作首先要解决软件包的依赖需要。
有了这些特性,人们在不知不觉中删除系统的包或者一些重要信息的几率将大大降低。


==========
=====================
An Overview of Dependencies    依赖关系的概述
我们已经提及到RPM处理依赖的一些潜在概念。它基于两个关键的因素:
<1>软件包通告他们提供的功能。
<2>软件包通告他们需要的功能。
通过简单的检测这两个类型的信息,可以避免很多问题。举个例子,如果一个包需要的一个功能但是系统中所有已经安装的软件包并未提供这个功能,这个软件
包将被安装,或者即使你强制安装也将不能正常工作。


另一方面,如果一个包被卸载,但是他自己提供的功能被另外的已安装的软件包需要,他就不能被卸载而导致其他软件包的失败。
正如你想的,没那么简单(唱起来!!)然而添加依赖信息可以很简单。事实上很多时候这个过程是自动的。


===========
=======================
Automatic Dependencies    自动依赖
当一个包被RPM编译构建,这包的文件列表中的任何文件都是一个共享库,这个库中的所有soname 动态库会自动添加到包所提供的功能列表中去。这里的soname的名称用于决定库的不同版本之间兼容性。


值得注意的是这并不是一个文件名。在实际中,任何方面RPM处理依赖是基于文件名的。很多新接触RPM的人经常会假设一个失败的依赖代表缺少一个文件。这并非如此。


记住RPM对依赖信息的处理是基于知道那个功能由那个包提供以及那个功能被软件包需要。我们已经看到RPM是如何自动决定一个包提供的共享库资源。但是他是怎么决定共享库包需要什么的?


yes!是这样的,RPM通过运行ldd命令在软件包的文件列表中的每一个可执行程序上。因为ldd可以提供每一个程序所需要的共享库列表。我们可以假设为一个等式,等式的两边是这样的---软件包提供共享库,软件包也需要这些共享库,这些都被RPM追踪。
RPM在软件包安装、升级或者卸载的时候会考虑这些信息。


================
========================
The Automatic Dependency Scripts   自动依赖脚本
RPM使用两个脚本来处理自动依赖过程。他们位于/usr/lib/rpm/下面分别是/usr/lib/rpm/find-requires 和 /usr/lib/rpm/find-provides;我们在下面会来看一下这两个脚本。
但首先让我们看看为什么会有脚本做这样的事情。这个脚本内置在RPM本身中岂不更好。
实际上创建脚本来做这样的事情是一个好主意。原因呢?RPM已经被移植到各种不同的操作系统上。确定那个共享库在执行时需要,共享库的名称,很简单,但是从一个操作系统到另一个操作系统具体的步骤差别比较大。所以说将RPM的这部分放在
一个脚本中更有利于移植,增强RPM的可移植性。虽然RPM由redhat公司开发,但其本质还是开源软件,就要具备开源软件的一些特性。


我们下面来看一下linux系统中的这两个脚本的实现。


-------find-requires — Automatically Determine Shared Library Requirements
-------find-requires — 自动确定需要的共享库。


在linux中的find-requires脚本是非常简单的:
---------------------------------------------------------------------------
#!/bin/sh


# note this works for both a.out and ELF executables


ulimit -c 0


filelist=`xargs -r file | fgrep executable | cut -d: -f1 `


for f in $filelist; do
    ldd $f | awk '/=>/ { print $1 }'
done | sort -u | xargs -r -n 1 basename | sort -u
---------------------------------------------------------------------------
该脚本首先创建一个可执行文件的列表。然后,为列表中的每个文件使用ldd确定共享库的需要并产生soname 列表。
最后,sonam的列表被删除,并删除任何路径。--这里我不太明白???


------find-provides — Automatically Determine Shared Library Sonames
------find-provides — 自动确定共享库的名称soname。
find-provides脚本相对稍微复杂,但仍然非常简单:
---------------------------------------------------------------------------
#!/bin/bash


# This script reads filenames from STDIN and outputs any relevant
# provides information that needs to be included in the package.


filelist=$(grep ".so" | grep -v "^/lib/ld.so" | 
xargs file -L 2>/dev/null | grep "ELF.*shared object" | cut -d: -f1)


for f in $filelist; do
    soname=$(objdump -p $f | awk '/SONAME/ {print $2}')


    if [ "$soname" != "" ]; then
        if [ ! -L $f ]; then
            echo $soname
        fi
    else
        echo ${f##*/}
    fi
done | sort -u
---------------------------------------------------------------------------
首先,创建一个共享库列表。为列表上的每个文件,提取soname,清理,重复删除。


=========
=====================
Automatic Dependencies: An Example  自动依赖的一个例子
让我们用广泛使用的程序 ls 来作为一个例子。在redahat linux操作系统上,ls 是 coreutils 的软件包的部分功能,安装在/bin/ls ;较老版本这个包为fileutils 。
我们来看看 coreutils 包的部分ls构建并执行 find-requires 。我们看到下面的显示:
****值得注意的是我在看这篇文章的时候,下面的脚本运行并不会像下面一样出现依赖的共享库
soname,maybe 新版本有所改动,我还在查看?????。
---------------------------------
# find-requires
/bin/ls
<ctrl-d>
libc.so.5
#
---------------------------------
当然下面的输出是正常的。
----------------------------------
# rpm -q --requires  coreutils
...
...   
libc.so.6()(64bit)
...
...
------------------------------------


$ rpm -q --provides glibc
.....
.....
这一块的理解还需要进一步,所以这里写的比较简单,期待我的进一步前进。




==========
====================
The autoreqprov, autoreq, and autoprov Tags — Disable Automatic Dependency Processing
The autoreqprov, autoreq, and autoprov 标签 -禁用自动依赖处理。
有时候RPM的自动依赖处理并不是我们所想要的结果。这种情况下,autoreqprov, autoreq, and autoprov这几个标签可以来禁用自动依赖处理。
这个标签需要是的yes/no或0/1的值。比如说,禁用自动以来处理应该这么做:
--------------------------
AutoReqProv: no
--------------------------
 autoreq and autoprov 两个标签可以分别用来禁用自动处理需要的或者提供的自动依赖处理。
 
 ************
 ***************************
 Manual Dependencies    手动处理依赖
 您可能已经注意到,我们已经使用单词“requires”和“provides”来描述包之间的依赖关系。事实上,在spec文件中使用这些单词标记来手工添加依赖信息是非常准确的。
 我们来看第一个标签 --Requires
 
 -----The Requires Tag 标签--requries
 当讨论到底一个包需要什么时我们一直在刻意模糊的描述。尽管我们使用“capabilities”功能这个词,实际上手动依赖需求代表一个包的需要。比如说,一个包foo需要另一个包bar被安装,
 我们可以在spec文件中这样来写:
 -------------------------
 Requires: bar
 --------------------------
之后再foo被安装时,RPM将会认为foo的依赖需要被满足如果任何版本的bar软件包已经被安装。【1】


如果更多的软件包被需要,他们可以一个接一个被添加在requires 标签后面并使用逗号或者空格 “ ','\' ' ” ;所以说如果软件包需要软件包bar, baz,下面的行将达到目的:
---------------------------
Requires: bar, baz
---------------------------
只要安装任何版本的bar, baz, foo软件包的依赖将被满足。


-----Adding Version Requirements  添加版本依赖需要 
当一个包有更严格的依赖需求,可以要求特定版本的包要被安装。所以必要做的是添加所需的版本号,可以使用比较符号:
<1>需要包版本低于指定的版本。
<2>需要包版本低于或者等于指定的版本。
<3>需要包版本等于指定的版本。
<4>需要包版本大于或者等于指定的版本。
<5>需要包版本大于指定的版本。
继续我们的例子,让我们猜猜所需的版本的包实际上需要至少是2.7;并且baz包必须为2.1版本——其他的版本都不行;下面看看:
------------------------------------------
Requires: bar >= 2.7, baz = 2.1
------------------------------------------
我们可以更具体要求需要一个特定版本的包:
------------------------------------------
Requires: bar >= 2.7-4, baz = 2.1-1
------------------------------------------


========
=====================
When Version Numbers Aren't Enough   版本号并不能满足时
你可能会认为所有这些特性,RPM的依赖处理可以处理所有可能的情况。你是正确的,除了版本号的问题。
RPM需要能够确定哪些版本号比其他更最近而去执行版本比较。很简单的决定,1.5版本比1.6版老。但是2.01和2.1呢?或7.6a 和 7.6 呢?
RPM没有保证所有的不同版本编号方案都可以使用。但是有一个解决方案;事实上… 有两个!!呵呵


-------Solution Number 1: Epoch numbers    解决方案一:Epoch 编号
如果RPM不能解释一个包的版本号该怎么办呢?是时候推出Epoch标签了。这个标签是用来帮助RPM确定版本号排序,下面是一个使用Epoch 标签的示例:
----------------
Epoch: 42
----------------
这一行表明,包有一个时期标签为42 。那么42是什么意思?只有这个版本的包比相同包一个时期标签为41的更新,但比同一个包的时期标签为43的较老旧一些。
如果你觉得时期标签的数字编号只不过是一个简单的版本号,那你就理解错了。换句话说,Epoch是一个关于RPM包的完整版本标识符的版本比较算法最重要的组成部分。
为了指示RPM依据Epoch而不是版本号进行依赖检查时,有必要使用冒号“:”在版本好前面。
-----------------------------
Requires: foo = 42:
-----------------------------
如果foo包需要一个时期标签Epoch 大于或等于42的:
------------------------------
Requires: foo >= 42:
------------------------------
如果foo包需要版本的时期标签Epoch编号42和版本号为1.0,这行可以这么写:
--------------------------------
Requires: foo >= 42:1.0
--------------------------------
你必须包括需要的时期标签Epoch如果它存在于包中。使用时期编号Epoch看起来似乎是很多额外的麻烦,的确你是对的。
但是也有另外一种方式帮你解脱:


--------Solution Number 2: Just Say No! 第二种解决方案:Just Say No! 要敢于说不!!!哈哈
如果你有改变软件的版本编号方案之间的选择,或在RPM中使用Epoch 编号,请考虑改变版本编号这一方案。很有可能,如果RPM也解释不了你的版本方案,那么
很大程度上使用你的软件的用户也不能很好的理解。但是如果没有软件的作者打包,和它的版本编号方案给RPM,Epoch的标签可以帮助你。


-------Fine Grained Dependencies  细粒度的依赖关系


对于绝大多数的依赖性,使用正常的Requires就够了。然而,有一些特殊的情况下,有人可能会想要更多细粒度的控制。
当在一个事务中多个包被安装,安装顺序和在这种情况下的依赖循环。在一个事务内卸载的顺序和包安装顺序是相反的。
一个非常微不足道的依赖循环的例子是,当包foo需要包baz,baz需要foo。然而,随着参与循环的包数量的增加,循环变得越来越复杂
本章特别依赖类型RPM的最好的提示。????根据经验,最好尽量避免完全依赖循环。然而,在一些罕见的情况下,他们可能渴望这么做。
-------------The PreReq Tag  
PreReq标签和Requires标签是一样的,本来还有一个额外的属性。使用它用来告诉RPM标记为PreReq的包应该在包含的依赖之前安装包。
然而,RPM版本4.4,这个特殊的属性将被被淘汰。和PreReq,Requires将很快没有功能的差异(在此时我写这篇文档时已经没有差异了吗????)。


纯需要足以确保正确的安装顺序如果在没有依赖循环的事务。如果依赖循环存在和无法避免,打包者应该努力构建他们的安装的顺序无关紧要的这样相互依赖的包。




---------Context Marked Dependencies  上下文明显依赖关系
最新版本的RPM支持上下文依赖性,这是一种特殊类型的一个依赖项,仅适用于指定的上下文。使用该功能,可以指定依赖项pre-和post(un)install 脚本,等。
上下文的依赖是一个指定的脚本的执行时间,指定这些依赖项的语法是:
------------------------
Requires(X): foo
------------------------
这里,X可以pre之一,post,preun,或postun,可以告诉RPM包取决于包foo运行对应的 %pre, %, %preun 或 %postun 脚本。
在实际中,RPM执行上面的依赖,直到指定的脚本运行。换句话说,它将允许删除标记为如依赖。%post脚本处理已经安装的包,但是不允许擦除一个%postun所需脚本包。
这可以减少混乱,这个是有点奇怪,RPM告诉安装一个包为了卸载另一个包。


--------------The Conflicts Tag 冲突标签
Conflict 的标签是在逻辑补充 Requires 标签的。它用于指定包与当前那个软件包冲突。RPM安装包不允许冲突,除非使用 --nodeps 选项覆盖安装。
Conflicts 标记和 Requires 有相同的格式:它接受一个真实或虚拟包名也可以包括版本和发布号或一个Epoch数字编号。




-------------The Provides Tag 
现在您已经了解了如何使用 Requires 标签。你可能希望你需要使用 Provides 标签在每一个包中。毕竟,RPM必须从某个地方获得这些包名,对吗?
虽然RPM确实需要有可用的包名, Provides 标签通常不是必需的。它可能会是多余的,因为RPM数据库已经包含安装每个程序包的名称。不需要再重复这一信息。
但是等等--我们早些时候说,手动依赖需求总是需要表示这些包。如果RPM不需要打包者使用 Provides 标签提供包的名称,那么 Provs 标签用来干什么?


-------------
----------Virtual Packages  虚拟包
进入虚拟包。虚拟包只不过是 Provides 标签指定一个名称。虚拟包方便在一个包需要特定的功能,而此功能可以由任何一个包提供。这里有一个例子:
为了正常工作,sendmail 需要本地投递代理来处理邮件发送。有许多不同的地方投递代理可用,--sendmail会工作的很好。


在这种情况下,它是没有意义的强制使用一个特定的本地投递代理;只要安装,sendmail的需求将被满足。所以 sendmail 的打包者添加以下行到 sendmail 的spec文件:
------------------------------------
Requires: lda
------------------------------------
没有包可以使用这个名字,所以sendmail的要求必须由一个虚拟的包满足。
------------------------------------
Provides: lda
------------------------------------
(注意,虚拟包可能没有版本号。)现在,当安装sendmail时,只要有一个安装包提供了lda虚拟包,就不会有问题。


【1】只要‘要求’和‘提供’使用相同的调用安装RPM,依赖项检查就会成功。例如,命令rpm -ivh *。rpm将妥善检查依赖关系,只要需求的包已经在提供的包之前被安装




==================================
===============================================
To Summarize…   小结
RPM的依赖处理是基于跟踪包提供的功能和包安装要求的功能。
一个包的需求可以来自两个地方:
<1>共享库的需求,由RPM自动处理。
<2>Requires 标记后面的,手动添加到包的spec文件中。
这些需求可以通过使用RPM的 --Requires 选项查询。个特定的需求可以被使用 --whatrequires查询选项。第五章中描述了这两个选项。


包提供的功能,可以来自三个地方:
<1>共享库sonam,自动由RPM。
<2>Provides 标签行,手动添加到包的spec文件。
<3>包的名字(和可选的,版本/时期Epoch编号)。


前两种类型的信息可以通过使用RPM的 --provides 查询选项。 一个特定的功能可以被使用 --whatprovides查询选项。第五章中描述了这两个选项的使用。


包的名称和版本应该考虑功能明确,因此,如果搜索使用 --Provides 或 --whatprovides 出现不了有用信息,尽量简单的方法就是按照包的名称寻找(当然这不是
科学的方法,但是我们时常会这么做)。


正如你可能已经了解到现在,使用手工之间需要一定程度的同步包的依赖关系。这可能会非常棘手,特别是如果你不负责这两个包。
但RPM的依赖处理可以使用户的生活变得更简单!!!!






**********************
*****************************************
@@@@@@@@@@@欢迎来到第十九章,也许你正在想办法给自己的非X86架构构建rpm软件包,如果你还有一些疑问,那么尝试来阅读本章吧,
也许随着你往后的浏览一些搁在你心头的疑问会无形中柳暗花明哦!!废话不多说了!!!


Chapter 19. Building Packages for Multiple Architectures and Operating Systems
第十九章---构建多平台的软件包
尽管我们已经看到RPM使得软件的打包变得更简单,但他不仅仅如此。RPM还为我们提供了在不同类型的计算机平台上构建软件包的工具。更有趣的是,RPM使我们在
不同计算机平台(架构)上的软件包的构建都只使用唯一的spec文件。所以我们只需要维护一套源文件就可以来为不同的种类的计算机平台开发软件包,此方式很大程度上便捷了我们的开发过程,缩短了开发周期。


在我们了解RPM的这一功能之前,我们先来快速回顾一下什么是不同类型的计算机系统的软件开发。


--------Architectures and Operating Systems: A Primer
--------架构和操作系统:
从软件工程的角度来看,任何两个计算机系统之间两个大的区别就是:
<1>计算机硬件实现的体系结构。
<2>计算机上运行的系统软件。
第一个区别内置于某台计算机本身,也就是说由生产商最初决定。体系结构是计算机系统(硬件系统)设计的一种方式。它包括处理器核中一定数量和类型的寄存器,指令集的数量,执行什么操作等等。比如我们大家都是用的
个人pc,不管哪个厂商的但都是是基于intel的X86体系结构的。


第二个区别更在我们的控制之下。操作系统是控制计算机如何运行的软件。不同的操作系统可能会以不同方式来管理和存储信息到存储介质,使用程序来实现不同的功能和硬件需求。


就软件包的构建而言,两个不同的环境比如说,同样的体系结构运行不同的操作系统软件和两个不同的体系结构运行相同的操作系统软件是不同的。第一种情况下,在不同的操作系统上打包会有不同的差异。
在第二种情况下,不同的体系结构的软件打包将由底层硬件的差异不同而不同。


RPM同样支持架构和操作系统的差异。如果有一个标签,rpmrc文件入口,或条件,用于支持建筑差异,也应该有相应的标签,条目,或条件,支持操作系统的差异。


----我们这里使用平台这个词来描述不同体系结构
为了保持最小重复在本章,我们将参考给定体系结构的计算机运行一个给定的操作系统平台。如果与其他的系统在各方面都有差异,我们就认为是不同的平台。


好嘞!!既然我们已经做了关于多平台的回顾和预热,下面我们就该一睹RPM的多平台功能特性。


【1】这是一个比较简单的问题,因为不兼容性在于不同体系结构上相同的操作系统软件的不同实现上。




===========
====================


--------What Does RPM Do To Make Multi-Platform Packaging Easier?
-------RPM是怎么来简化多平台的软件打包的??
正如前面我们所讨论的,RPM是通过一系列标签来支持多平台的软件包构建的,rpmrc文件的中的条目和一些条件标签。这些工具是很难使用。
而事实上相对比较艰难的部分是如何修改软件代码来支持多平台软件包的构建。


我们来看看RPM都提供了哪些工具来支持多平台软件包的构建。


-------Automatic Detection of Build Platform
-------自动检测编译平台
首先要做的必要且易于多平台包的构建的事情就是识别出为那个平台构建软件包。除了深奥的交叉编译的情况,编译平台就是在那个平台上编译软件包。???
虽然这一动作在build阶段可以被复写,RPM还是可以为你自动化这一部分。
RPM does this for you automatically, although it can be overridden at build-time


--------Automatic Detection of Install Platform
--------自动检测安装平台
其次较为重要的是在构建的的平台上的打包的软件包要在那个平台上安装。和上面类似,虽然此过程可以在安装阶段被覆写,RPM还是可以自动的为你做这些事情。


但多平台包构架不仅仅是能够在包的构建和安装期间确定平台。我们也可以使用一组和平台相关的标签。


-----Platform-Dependent Tags
-----平台相关的标签
RPM使用若干标签来控制具体为那个平台构建软件包。这些标签大大方便了包的构建者构建多平台的软件包,因为这些标签会阻止RPM为不兼容的平台构建包。


------Platform-Dependent Conditionals
------平台相关的条件
虽然与平台相关的标签提供较粗糙级别的多平台控制(比如,包是否被构建取决于标签和构建平台),这里RPM与平台相关的条件提供了一种更为精细的控制。通过
使用这些条件,本来要移除某些其他平台在spec文件中的对应内容的部分可以被替换为一行或者多行兼容其他平台的语句。(就如同if-else语句)


至此,我们已经了解了RPM支持多平台的一些基本特性,下面我们来更深入的理解其中的玄机!!


================
============================
-----Build and Install Platform Detection
-----构建和安装检测
正如我们上面提到的,多平台方案建设的第一步是确定构建平台。这是通过匹配信息构建系统的uname输出与rpmrc大量文件条目。
通常情况下,这是没有必要过于担心的,rpmrc文件条目的RPM附带了一组支持所有平台的条目。然而,当添加对新平台的支持,
它将需要使用以下条目添加支持新的构建平台。


----Platform-Specific rpmrc Entries
----平台指定的rpmrc 文件条目
一般情况下,文件/usr/lib/rpm/rpmrc包含以下rpmrc 文件条目。它们可以被/etc/rpmrc或~ /.rpmrc条目复写。这部分内容会子啊附录B中全面的讨论。
因为每个条目的类型对体系结构和操作系统的特性都是有效的,所以我们下面在arch或者os指定的地方使用xxx来代替描述。


xxx_canon — Define Canonical Platform Name and Number
------------定义标准平台的名称和编号
条目xxx_canon 用于转换从运行RPM的操作系统获取的条目信息为标准的名称和编号以用于RPM内部使用。按照下面格式:
---------------------------------------
xxx_canon: <label>: <string> <value>
---------------------------------------
这里的label会和系统中uname命令的输出比较。如果匹配,那么string就会被RPM作为标准名称,value会被用来作为唯一编号值。看个例子:
----------------------------------
arch_canon: sun4:  sparc  3
os_canon:  Linux:  Linux  1
# This is really a place holder for MIPS.
arch_canon:     mips:   mips    4
----------------------------------
上面的 arch_canon 标签用来为 Sun Microsystems' SPARC 体系结构定义标准的体系结构信息。在这个例子中 uname 命令的输出将会和 sun4来比较。如果匹配,标准的体系结构名称(name)就会被设置为sparc以及体系结构编号将会设置为3.


上面 os_canon 标签用于为linux操作系统定义标准的操作系统信息。这个例子中uname的输出会与 Linux 比较。如果匹配,标准操作系统名称(name)会被设置为Linux以及操作系统编号会被设置为1.


我们上面的描述不是百分之百的完整----这里可以有额外的动作在RPM使用的uname命令获取系统信息并且和标准名称比较。下面我们来看一下rpmrc文件中的条目是如何在中间步骤发挥作用的。




--------buildxxxtranslate — Define Build Platform
--------定义构建平台
条目 buildxxxtranslate 用于定义构建平台信息。具体地说,这些条目是用来创建一个表,信息从uname映射到适当的架构/操作系统名称。


条目 buildxxxtranslate 的格式如下所示:
--------------------------------------
buildxxxtranslate: <label>: <string>
--------------------------------------


这里的label会与uname的输出比较。如果发现匹配,那么 string 被RPM用来作为构建平台信息,之后xxx_canon作为标准的构建平台。
-----------------------------------------
buildarchtranslate: i586: i386
buildostranslate: Linux: Linux
-----------------------------------------
这里 buildarchtranslate 标签用于定义构建体系结构为 Intel Pentium 处理器。默认情况下任何基于奔腾的系统使用Intel 80386体系结构。
这里的 buildostranslate 标签用来定义linux操作系统作为运行构架的系统。在这种情况下,构建操作系统保持不变。


--------xxx_compat — Define Compatible Architectures
-----------\--------定义兼容的体系结构
这里的 xxx_compat 条目用于定义架构和操作系统兼容。只是在安装时使用。条目的格式是:
---------------------------------------
xxx_compat: <label>: <list>
---------------------------------------
这个里的<label>是一个在xxx_canon 条目中定义的名称。<list>后由一个或多个名称,是由arch_canon 定义的。如果在列表中有一个以上的名称,应该用空格分隔。
列表中的名称可以认为是和标签中指定的名称兼容的体系结构或操作系统。
---------------------------------------
arch_compat: i586: i486
arch_compat: i486: i386
os_compat: Linux: AIX
---------------------------------------
上面所示的arch_compat行说明一组向上兼容的体系结构如何来表示。例如,如果构建架构定义为一个i586系统,兼容的体系结构将i486和i386。
然而,如果构建系统是i486,唯一兼容的体系结构将是一个i386。


上面所示的os_compat 行完全是虚构的,它的目的是宣布AIX与Linux兼容。


---------Overriding Platform Information At Build-Time
---------在构建时覆盖平台信息
通过使用上面所讨论的rpmrc文件条目,RPM通常要选择作出正确的构建和安装平台。然而,可能有时候RPM的选择并不是最好的。通常在使用交叉编译软件情况下不能按早寻常情况来处理。
在这些情况下,有一个有趣简单的方法就是覆盖构建时架构和操作系统信息。


这里 --buildarch和--buildos选项可用于设置构建时架构和操作系统信息而不是依靠RPM的自动检测功能。
【注意】我在前面的章节已经提醒过读者,在新版本的RPM中,是没有两个选项的,取而代之的是 --target选项。
此选项的使用说明如下:
----------------------------------------------------------------------------------------
The --target option sets the spec file macros %_target, %_target_arch, and %_target_os .
For example:
$ rpmbuild -bc --target ppc-ibm-aix /usr/src/redhat/SPECS/jikes.spec
----------------------------------------------------------------------------------------


包括安装时的平台相关的信息 --ignorearch 和 --ignoreos选项新版本中也已经移除。


底线是:除非你知道你为什么需要使用 --target ,否则你可能不需要使用它们


============
=======================
--------optflags — The Other rpmrc File Entry
这也是rpmrc 文件的一个条目。尽管optflags条目并不参与确定构造或安装平台,但它在多平台包的构建中发挥作用。
optflags条目用于定义一组标准的选项,可以在构建过程中使用,特别是在编译时。


optflags条目如下:
----------------------------------
optflags: <architecture> <value>
-----------------------------------
例如,假设以下optflags条目被添加进在一个rpmrc文件:
------------------------------------------------
optflags: i386 -O2 -m486 -fno-strength-reduce
optflags: sparc -O2
------------------------------------------------
如果RPM运行在一个Intel 80386兼容的体系结构,那么 optflags 值应该设置为-O2 -m486 -fno-strength-reduce。如果RPM运行在Sun SPARC-based系统上, optflags 该被设置为 -O2 .
这个条目会设置 RPM_OPT_FLAGS 环境变量,此变量可以被用于%prep, %build, and %install 几个脚本阶段。




=========
==========================
--------Platform-Dependent Tags   平台相关的标签
一旦RPM确定构建平台的信息,这些信息可以用于构建过程。第一种方法是此信息用来决定一个给定的包是否应该在给定的平台上构建。这里可以使用四个标签在你的spec文件中。


这里有很多可能的原因。比如,软件在指定的平台上没有构建成功。或者说是一个指定平台的,但是构建时是在其他平台上,虽然技术上是可能的,但是这么做没有什么实际意义。


现实世界并不总是那么有条理的,所以甚至可能有一个包的情况应该是建立在三个不同的平台。细心的使用以下标签,你可以应对任何可能的情况。


如我们已经讨论过的rpmrc文件中的条目,这里有相同的对不同体系结构和操作系统的标签,我们下面一起来探讨这些内容:


---------The excludexxx Tag
这里的 excludexxx 标签用来驱使RPM确保不会在这一行指定的平台或系统上构建软件包,多个平台或者操作系统可以使用逗号或者空格来分隔。看两个示例:
----------------------------------
ExcludeArch: sparc alpha
ExcludeOS: Irix
----------------------------------
第一行阻止RPM在基于 Sun SPARC 和 Digital Alpha/AXP 体系结构的系统上构建软件包。第二行确保我们将不会在Silicon Graphics的Irix操作系统上执行构建任务。 
如果一个构建任务试图在排除的体系结构或者操作系统上执行构建,你会看到下面的警告以及构建失败的结果。
-----------------------------------------------------
# rpmbuild -ba cdplayer-1.0.spec
Arch mismatch!
cdplayer-1.0.spec doesn't build on this architecture

-------------------------------------------------------
这里的excludexxx 标签是为了明确的阻止为一组限定的体系结构和操作系统构建软件包。如果你的目标是确保一个包只会构建一个架构,那么你应该使用exclusivexxx标签。


---------The exclusivexxx Tag  为包含的体系结构或者os执行构建
这里的exclusivexxx 标签用来驱使RPM只为指定的体系结构或者os执行构建任务。这些标签确保,在未来,没有全新的平台将错误地尝试构建方案。
RPM将只在指定的平台上执行软件包的构建。
这里的exclusivexxx标签的用法和上面的excludexxx相同:
---------------------------------
ExclusiveArch: sparc alpha
ExclusiveOS: Irix
----------------------------------
第一行表示RPM将只会在 Sun SPARC 或者 Digital Alpha/AXP 体系结构上执行软件包的构建。第二行表示只会在Irix 操作系统上执行软件包的构建。


这里的 exclusivexxx 标签是为了明确的允许为一组限定的体系结构和操作系统构建软件包。如果你的目标是确保一个包不会在一个指定的平台构建,那么你应该使用 excludexxx 标签。


















 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值