/usr/var
(5) 创建RPM包的例子
要创建的rpm包为:test-1.0.1-1.el6.i686.rpm,打包的压缩文件为:test-1.0.1.tar.gz。 1.把test-1.0.1.tar.gz拷贝到SOURCE目录底下。
2.转至SPECS目录底下,编写test.spec描述文件,这个文件是创建rpm包最重要的部分,它会制定rpm包里的软件的安装目录,以及安装软件前后要注意的问题,软件的依赖及系统要求。
3.编译RPM,执行命令:rpmbuild –ba test.spec。这样以后,就开始创建rpm包。
4.执行rpmbuild –ba test.spec后,会首先把test-1.0.1.tar.gz解压缩到BUILD目录,BUILDROOT这个目录用来存放执行时存放的临时文件夹,这个目录也很重要,需要把在此目录建立相关目录以及拷贝相关文件信息的脚本写入test.spec文件里,以防编译出错,无法生成RPM包。成功执行完成之后,会在RPMS这个目录生成i686/ test-1.0.1-1.el6.i686.rpm文件。
如下图:
(6) 附加SPEC文件
文件是官方发布的anaconda.spec,Anaconda是RedHat、CentOS、Fedora等Linux的安装管理程序,以后还有很重要的应用。分析该文件对系统的定制很有帮助,因文件内容过长,删除后面不太重要的日志部分。
%define livearches %{ix86} x86_64 ppc ppc64
%define _libdir %{_prefix}/lib
Summary: Graphical system installer
Name: anaconda
Version: 13.21.176
Release: 1%{?dist}
License: GPLv2+
Group: Applications/System
URL: http://fedoraproject.org/wiki/Anaconda
# To generate Source0 do:
# git clone http://git.fedorahosted.org/git/anaconda.git
# git checkout -b archive-branch anaconda-%{version}-%{release}
# ./autogen.sh
# ./configure
# make dist
Source0: %{name}-%{version}.tar.bz2
Patch1000: anaconda-centos-installclass.patch
Patch1001: anaconda-centos-upgrade-from-centos.patch
Patch1002: anaconda-centos-droprepos.patch
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
# Versions of required components (done so we make sure the buildrequires
# match the requires versions of things).
%define dmver 1.02.17-6
%define gettextver 0.11
%define genisoimagever 1.1.9-4
%define intltoolver 0.31.2-3
%define libnlver 1.0
%define libselinuxver 1.6
%define pykickstartver 1.74.8
%define rpmpythonver 4.2-0.61
%define slangver 2.0.6-2
%define yumver 2.9.2
%define partedver 1.8.1
%define pypartedver 3.0
%define syscfgdatever 1.9.48
%define pythonpyblockver 0.45-2
%define e2fsver 1.41.0
%define nmver 1:0.7.1-3.git20090414
%define dbusver 1.2.3
%define createrepover 0.4.7
%define yumutilsver 1.1.11-3
%define iscsiver 6.2.0.870-3
%define pythoncryptsetupver 0.0.6
%define mehver 0.8
%define sckeyboardver 1.3.1
%define libblkid 2.17.1-1
%define fcoeutilsver 1.0.12-3.20100323git
%define isomd5sumver 1.0.6
BuildRequires: audit-libs-devel
BuildRequires: bzip2-devel
BuildRequires: device-mapper-devel >= %{dmver}
BuildRequires: e2fsprogs-devel >= %{e2fsver}
BuildRequires: elfutils-devel
BuildRequires: gettext >= %{gettextver}
BuildRequires: gtk2-devel
BuildRequires: intltool >= %{intltoolver}
BuildRequires: isomd5sum-devel >= %{isomd5sumver}
BuildRequires: libarchive-devel
BuildRequires: libX11-devel
BuildRequires: libXt-devel
BuildRequires: libXxf86misc-devel
BuildRequires: libblkid-devel >= %{libblkid}
BuildRequires: libcurl-devel
BuildRequires: libnl-devel >= %{libnlver}
BuildRequires: libselinux-devel >= %{libselinuxver}
BuildRequires: libsepol-devel
BuildRequires: libxml2-python
BuildRequires: newt-devel
BuildRequires: pango-devel
BuildRequires: pykickstart >= %{pykickstartver}
BuildRequires: python-devel
BuildRequires: python-urlgrabber >= 3.9.1-5
BuildRequires: rpm-devel
BuildRequires: rpm-python >= %{rpmpythonver}
BuildRequires: slang-devel >= %{slangver}
BuildRequires: xmlto
BuildRequires: yum >= %{yumver}
BuildRequires: zlib-devel
BuildRequires: NetworkManager-devel >= %{nmver}
BuildRequires: NetworkManager-glib-devel >= %{nmver}
BuildRequires: dbus-devel >= %{dbusver}
BuildRequires: system-config-keyboard >= %{sckeyboardver}
%ifarch %livearches
BuildRequires: desktop-file-utils
%endif
BuildRequires: iscsi-initiator-utils-devel >= %{iscsiver}
%ifarch s390 s390x
BuildRequires: s390utils-devel
%endif
Requires: python-meh >= %{mehver}
Requires: policycoreutils
Requires: rpm-python >= %{rpmpythonver}
Requires: comps-extras
Requires: parted >= %{partedver}
Requires: pyparted >= %{pypartedver}
Requires: yum >= %{yumver}
Requires: libxml2-python
Requires: python-urlgrabber >= 3.9.1-5
Requires: system-logos
Requires: pykickstart >= %{pykickstartver}
Requires: system-config-date >= %{syscfgdatever}
Requires: device-mapper >= %{dmver}
Requires: device-mapper-libs >= %{dmver}
Requires: dosfstools
Requires: e2fsprogs >= %{e2fsver}
Requires: gzip
Requires: xz
Requires: libarchive
%ifarch %{ix86} x86_64 ia64
Requires: dmidecode
%endif
Requires: python-pyblock >= %{pythonpyblockver}
Requires: libuser-python
Requires: newt-python
Requires: authconfig
Requires: system-config-firewall-base
Requires: cryptsetup-luks
Requires: python-cryptsetup >= %{pythoncryptsetupver}
Requires: mdadm
Requires: lvm2
Requires: util-linux-ng >= 2.15.1
Requires: system-config-keyboard >= %{sckeyboardver}
Requires: dbus-python
Requires: cracklib-python
Requires: python-nss
Requires: tigervnc-server
%ifarch %livearches
Requires: usermode
Requires: zenity
%endif
Requires: createrepo >= %{createrepover}
Requires: squashfs-tools
Requires: genisoimage >= %{genisoimagever}
%ifarch %{ix86} x86_64
Requires: syslinux >= 3.73
Requires: makebootfat
Requires: device-mapper
%endif
%ifarch s390 s390x
Requires: openssh
%endif
Requires: isomd5sum
Requires: yum-utils >= %{yumutilsver}
Requires: NetworkManager >= %{nmver}
Requires: dhclient
Requires: anaconda-yum-plugins
Requires: libselinux-python >= %{libselinuxver}
Requires: fcoe-utils >= %{fcoeutilsver}
%ifarch %{sparc}
Requires: elftoaout piggyback
%endif
Obsoletes: anaconda-images <= 10
Provides: anaconda-images = %{version}-%{release}
Obsoletes: anaconda-runtime < %{version}-%{release}
Provides: anaconda-runtime = %{version}-%{release}
Obsoletes: booty
%description
The anaconda package contains the program which was used to install your
system. These files are of little use on an already installed system.
%prep
%setup -q
%patch1000 -p1
%patch1001 -p1
%patch1002 -p1
%build
%configure --disable-static
%{__make} %{?_smp_mflags}
%install
%{__rm} -rf %{buildroot}
%{__make} install DESTDIR=%{buildroot}
find %{buildroot} -type f -name "*.la" | xargs %{__rm}
%ifarch %livearches
desktop-file-install --vendor="" --dir=%{buildroot}%{_datadir}/applications %{buildroot}%{_datadir}/applications/liveinst.desktop
%else
%{__rm} -rf %{buildroot}%{_bindir}/liveinst %{buildroot}%{_sbindir}/liveinst
%endif
%find_lang %{name}
%clean
%{__rm} -rf %{buildroot}
%ifarch %livearches
%post
update-desktop-database &> /dev/null || :
%endif
%ifarch %livearches
%postun
update-desktop-database &> /dev/null || :
%endif
%files -f %{name}.lang
%defattr(-,root,root)
%doc COPYING
%doc docs/command-line.txt
%doc docs/install-methods.txt
%doc docs/mediacheck.txt
%doc docs/anaconda-release-notes.txt
/lib/udev/rules.d/70-anaconda.rules
%{_sbindir}/anaconda
%ifarch i386 i486 i586 i686 x86_64
%{_sbindir}/gptsync
%{_sbindir}/showpart
%endif
%{_datadir}/anaconda
%{_prefix}/lib/anaconda
%{_prefix}/lib/anaconda-runtime
%ifarch %livearches
%{_bindir}/liveinst
%{_sbindir}/liveinst
%config(noreplace) %{_sysconfdir}/pam.d/*
%config(noreplace) %{_sysconfdir}/security/console.apps/*
%{_sysconfdir}/X11/xinit/xinitrc.d/*
%{_datadir}/applications/*.desktop
%{_datadir}/icons/hicolor/*
%endif
%changelog
* Sat Jun 23 2012 Karanbir Singh - 13.21.176.1.el6.centos
- Build for CentOS-6.3
(7) 升级RPM包的SPEC文件修改
当在用户机器上安装或卸载程序时,能够执行命令将是很有用的。例如,可能需要编辑一个系统配置文件以启用新的服务,或者需要定义一个新用户以拥有正在安装的程序的所有权。
安装和卸载脚本的工作原理看起来很简单,但它们工作原理中的一些意外可能会引起大问题。这里是一些基本信息,可以将下列四节中的任意一个添加到.spec 文件,它列出了在包安装期间各个点上运行的shell 脚本:
%pre 在安装包之前运行
%post 在安装包之后运行
%preun 在卸载包之前运行
%postun 在卸载包之后运行
尤其要注意%install与这些节之间的差异。构建RPM 时,%install 在开发机器上运行;它应该将产品安装在开发机器上或安装到一个构建根目录中。另一方面,这些节指定当用户正在安装或卸载RPM包时将在用户的机器上运行什么。
一种好的技术是使用%pre脚本来检查安装前提条件,它们比RPM可以直接支持的更复杂。 如果不符合前提条件,那么脚本以非零状态退出,而且 RPM 不会继续安装。另外请注意,我们必须小心地使用卸载脚本来撤销安装脚本。
然而实际上没有那么简单:升级使每件事情都变得复杂,现在,让我们着手升级。如果用户只安装和删除自己的包,那么前面的指令将正常工作;但在升级期间,它们会完全失效。以下是 RPM 如何执行升级:
运行新包的 %pre
安装新文件
运行新包的 %post
运行旧包的 %preun
删除新文件未覆盖的所有旧文件
运行旧包的 %postun
如果我们使用5.3.2系列中现有SPEC文件中的脚本来升级,那么RPM最后将运行 %postun 脚本,它将除去我们在安装脚本中所做的所有工作。
rpm为了解决此问题,在其英文文档中提到了可以向脚本来传递一个参数$1,这个参数传递的过程是隐藏的,你只需在%pre,%post,%preun,%postun中使用$1即可($1在shell中就是第一个参数的意思)。这个参数的含义是在执行完此次操作后系统中此软件包的剩余数量是多少,就目前我的理解应该只有0,1,2三种可能。
1.在执行rpm –ivh的安装过程中,如果有同类包存在,则会报错提示无法安装,存在相同的文件。如果没有同类包存在则会执行安装动作,过程如下:
运行新包的%pre $1=1
安装新文件
运行新包的%post $1=1
2.在执行rpm –U的升级过程中,如果没有同类低级包存在,则过程和传递的参数与安装时完全相同,如果有同类低级包存在则会执行升级操作,过程如下:
运行新包的%pre $1=2
安装新文件
运行新包的%post $1=2
运行旧包的%preun $1=1
删除新文件未覆盖的任何旧文件
运行旧包的%postun $1=1
3.在执行rpm –e的删除过程如下:
运行旧包的%preun $1=0
删除文件
运行旧包的%postun $1=0
因此我们可以用传递的参数来判断rpm究竟在进行什么工作,来在脚本内部通过$1进行判断来决定进行什么动作。例如在参数为0的时候才真的执行卸载所要进行的动作。
另外在升级的时候,除了注意几个脚本的执行顺序与结果外,还要注意配置文件的处理是否正确,RPM还有一项重要的工作要做,这就是妥善处理配置文件(CONFIG FILE)。若直接采用安装方式,则用户已配置好的配置文件就会被覆盖,不符合用户要求。
RPM对某个配置文件,通过比较三种不同的MD5检查和(checksum)来决定如何处理它。这三种不同的MD5检查和是:
1. 原检查和。它是旧版本软件包安装时配置文件的MD5检查和。
2. 当前检查和。它是升级时旧版本配置文件的MD5检查和。
3. 新检查和。它是新版本软件包中配置文件的MD5检查和。
RPM针对以下几种情况分别处理:
1. 当原检查和=X,当前检查和=X,新检查和=X时:
这表明配置文件未曾修改过。此时,RPM会将新的配置文件覆盖掉原文件,而不是对原文件不作处理,原因在于: 虽然文件名和文件内容都没有变化,但文件别的方面的属性(如文件的属主,属组,权限等)却可能改变,所以有必要覆盖一下。
2. 当原检查和=X,当前检查和=X,新检查和=Y时:
这表明原配置文件没有改动过,但是它与新软件包中的配置文件却有所不同。这种情况下,RPM将用新文件覆盖掉旧文件,并且旧文件不作保存(因为它不曾改动过,没有必要保存)。
3. 当原检查和=X,当前检查和=Y,新检查和=X时:
这表明新文件与旧文件内容相同,但当前文件已经作过修改,这些修改对于新版本来说应该是合法的,可以使用的。因此,RPM对当前文件予以保留。
4. 当原检查和=X,当前检查和=Y,新检查和=Y时:
这表明原文件经过修改,现在已与新文件相同,这或许是用户用来修补安全上的漏洞,新版本也作了同样的修改。这种情况下,RPM将新文件覆盖当前文件,避免文件属性方面的不同。
5. 当原检查和=X,当前检查和=Y,新检查和=Z时:
这表明用户已修改了原文件,并且当前内容与新文件内容不同。这种情况下,RPM无法保证新版本软件能正常使用当前的配置文件,所以采用了一个比较明智的办 法,既能保护用户的配置数据,又能保证新版本软件正常。这种作法就是将当前文件换名保存(给原文件名加个.rpmsave的后缀,如原文件名为ABC,则 换名后为ABC.rpmsave),同时安装新文件,并给出警告信息。
6. 当没有原检查和时:
此种情况下,当前检查和与新检查和已无关紧要,这表明没有安装过此配置文件。因为没有安装过此配置文件,所以RPM无法判断当前文件是否被用户修改过。这种情况下,RPM会将当前文件换名保存(原文件名后缀不是加个.rpmsave,而是.rpmorig),同时安装新文件,并给出警告信息。
因此在%files中可以用%config字段将配置文件标识出来,这样在升级的过程中配置文件将被按照上面所描述的方法处理。
%config 文件路径的形式来添加。
三、总结
(2)rpm和rpmbuild内容众多丰富,该博客总结部分内容,以便使用时能快速查找到。
(3)若有读者想沟通交流的,可发信息到邮箱yang.ao@i-soft.com.cn。