常见的Linux发行版主要可以分为两类,类ReadHat系列和类Debian系列,这里我们是以其软件包的格式来划分的,这两类系统分别提供了自己的软件包管理系统和相应的工具。类RedHat系统中软件包的后缀是rpm;类Debian系统中软件包的后缀是deb。另一方面,类RedHat系统提供了同名的rpm命令来安装、卸载、升级rpm软件包;类Debian系统同样提供了dpkg命令来对后缀是deb的软件包进行安装、卸载和升级等操作。
rpm的全称是Redhat Package Manager,常见的使用rpm软件包的系统主要有Fedora、CentOS、openSUSE、SUSE企业版、PCLinuxOS以及Mandriva Linux、Mageia等。使用deb软件包后缀的类Debian系统最常见的有Debian、Ubuntu、Finnix等。
无论是rpm命令还是dpkg命令在安装软件包时都存在一个让人非常头疼的问题,那就是软件包的依赖关系。这一点很多人应该深有体会,这也使初学者在接触Linux系统时觉得很不方便的地方。庆幸的是,很多发行版都考虑到了这问题,于是Fedora和CentOS提供了yum来自动解决软件包的安装依赖,同样的openSUSE提供了zypper,类Debian系统提供了apt-*命令。也就是说这些工具本质上最终还是调用了rpm(或者dpkg)是不过安装前自动帮用户解决了软件包的安装依赖。如下表所示:
分类 | 发行版 | 手动安装命令 | 自动安装命令 | 软件包后缀 |
类RedHat |
Fedora/CentOS | rpm |
yum | *.rpm |
openSUSE/SUSE | zypper | |||
Mandriva Linux/Mageia | urpmi | |||
类Debian | Debian/Ubuntu | dpkg | apt-get | *.deb |
简单点了说,如果你会在Fedora或者CentOS上用yum来自动安装软件包,那么在Debian或者Ubuntu上你就会用apt-get自动安装软件,同理,在openSUSE上你就会用zypper自动安装软件包。
本文档主要描述如何通过软件包的源代码构建自己的rpm软件安装包。
从软件运行的结构来说,一个软件主要可以分为三个部分:可执行程序、配置文件和动态库。当然还有可能会有相关文档、手册、供二次开发用的头文件以及一些示例程序等等。其他部分都是可选的,只有可执行文件是必须的。
关于如何制作rpm软件包的方法,网上教程也一大堆,谈及最多的当属rpmbuild这个命令行工具。这也是本文要介绍的“配角”,而主角是它的输入对象,也就是所谓的SPEC文件的格式,写法和说明。
rpm的打包流程相比deb的要稍微麻烦一些,因为它对打包目录有一些严格的层次上的要求。如果你的rpm的版本<=4.4.x,那么rpmbuid工具其默认的工作路径是/usr/src/redhat,这就使得普通用户不能制作rpm包,因为权限的问题,在制作rpm软件包时必须切换到root身份才可以。所以,rpm从4.5.x版本开始,将rpmbuid的默认工作路径移动到用户家目录下的rpmbuild目录里,即$HOME/rpmbuild,并且推荐用户在制作rpm软件包时尽量不要以root身份进行操作。
关于rpmbuild默认工作路径的确定,通常由在/usr/lib/rpm/macros这个文件里的一个叫做%_topdir的宏变量来定义。如果用户想更改这个目录名,rpm官方并不推荐直接更改这个目录,而是在用户家目录下建立一个名为.rpmmacros的隐藏文件(注意前面的点不能少,这是Linux下隐藏文件的常识),然后在里面重新定义%_topdir,指向一个新的目录名。这样就可以满足某些“高级”用户的差异化需求了。通常情况下.rpmmacros文件里一般只有一行内容,比如:
点击(此处)折叠或打开
在%_topdir目录下一般需要建立6个目录:
目录名 | 说明 | macros中的宏名 |
BUILD | 编译rpm包的临时目录 | %_builddir |
BUILDROOT | 编译后生成的软件临时安装目录 | %_buildrootdir |
RPMS | 最终生成的可安装rpm包的所在目录 | %_rpmdir |
SOURCES | 所有源代码和补丁文件的存放目录 | %_sourcedir |
SPECS | 存放SPEC文件的目录(重要) | %_specdir |
SRPMS | 软件最终的rpm源码格式存放路径(暂时忽略掉,别挂在心上) | %_srcrpmdir |
点击(此处)折叠或打开
点击(此处)折叠或打开
其实SPEC文件的核心是它定义了一些“阶段”(%prep、%build、%install和%clean),当rpmbuild执行时它首先会去解析SPEC文件,然后依次执行每个“阶段”里的指令。
接下来,我们来简单了解一下SPEC文件的头部。假如,我们的源码包名字是myapp-0.1.0.tar.gz,那么myapp-0.1.0.spec的头部一般如下的样子:
点击(此处)折叠或打开
下面我们来看一下制作rpm包的几个关键阶段,以及所发生的事情:
阶段 | 动作 |
%prep | 将%_sourcedir目录下的源代码解压到%_builddir目录下。如果有补丁的需要在这个阶段进行打补丁的操作 |
%build | 在%_builddir目录下执行源码包的编译。一般是执行./configure和make指令 |
%install | 将需要打包到rpm软件包里的文件从%_builddir下拷贝%_buildrootdir目录下。当用户最终用rpm -ivh name-version.rpm安装软件包时,这些文件会安装到用户系统中相应的目录里 |
制作rpm包 | 这个阶段是自动完成的,所以在SPEC文件里面是看不到的,这个阶段会将%_buildroot目录的相关文件制作成rpm软件包最终放到%_rpmdir目录里 |
%clean | 编译后的清理工作,这里可以执行make clean以及清空%_buildroot目录等 |
每个阶段的详细说明如下:
点击(此处)折叠或打开
当然,这句指令可以成功执行的前提是你位于SOURCES目录下的源码包必须是name-version.tar.gz的格式才行,它还会完成后续阶段目录的切换和设置。如果在这个阶段你不用这条指令,那么后面每个阶段都要自己手动去改变相应的目录。解压完成之后如果有补丁文件,也在这里做。想了解的童鞋可以自己去查查如何实现,也不难,这里我就不展开了。
点击(此处)折叠或打开
它就自动将软件安装时的路径自动设置成如下约定:
注意,这里的%configure是个宏常量,会自动将prefix设置成/usr。另外,这个宏还可以接受额外的参数,如果某些软件有某些高级特性需要开启,可以通过给%configure宏传参数来开启。如果不用 %configure这个宏的话,就需要完全手动指定configure时的配置参数了。同样地,我们也可以给make传递额外的参数,例如:
点击(此处)折叠或打开
这个阶段就是执行make install操作。这个阶段会在%_buildrootdir目录里建好目录结构,然后将需要打包到rpm软件包里的文件从%_builddir里拷贝到%_buildrootdir里对应的目录里。这个阶段最常见的两条指令是:
点击(此处)折叠或打开
其中$RPM_BUILD_ROOT也可以换成我们前面定义的BuildRoot变量,不过要写成%{buildroot}才可以,必须全部用小写,不然要报错。
如果软件有配置文件或者额外的启动脚本之类,就要手动用copy命令或者install命令你给将它也拷贝到%{buildroot}相应的目录里。用copy命令时如果目录不存在要手动建立,不然也会报错,所以推荐用install命令。
编译完成后一些清理工作,主要包括对%{buildroot}目录的清空(当然这不是必须的),通常执行诸如make clean之类的命令。
点击(此处)折叠或打开
在%files阶段的第一条命令的语法是:
点击(此处)折叠或打开
如果不牵扯到文件、目录权限的改变则一般用%defattr(-,root,root,-)这条指令来为其设置缺省权限。所有需要打包到rpm包的文件和目录都在这个地方列出,例如:
点击(此处)折叠或打开
在安装rpm时,会将可执行的二进制文件放在/usr/bin目录下,动态库放在/usr/lib或者/usr/lib64目录下,配置文件放在/etc目录下,并且多次安装时新的配置文件不会覆盖以前已经存在的同名配置文件。
这里在写要打包的文件列表时,既可以以宏常量开头,也可以为“/”开头,没任何本质的区别,都表示从%{buildroot}中拷贝文件到最终的rpm包里;如果是相对路径,则表示要拷贝的文件位于%{_builddir}目录,这主要适用于那些在%install阶段没有被拷贝到%{buildroot}目录里的文件,最常见的就是诸如README、LICENSE之类的文件。如果不想将%{buildroot}里的某些文件或目录打包到rpm里,则用:
点击(此处)折叠或打开
但是关于%files阶段有两个特性要牢记:
关于%doc宏,所有跟在这个宏后面的文件都来自%{_builddir}目录,当用户安装rpm时,由这个宏所指定的文件都会安装到/usr/share/doc/name-version/目录里。
点击(此处)折叠或打开
说了这么多,我们实战一下。网上很多教程都是拿Tomcat或者Nigix开头,这里我就先从简单的mp3解码库libmad入手,将它打成一个rpm包,具体步骤如下:
(如果自己系统上没有rpmbuild命令就安装之:yum install rpm* rpm-build rpmdev*)
3、在rpmbuild/SPECS目录下执行rpmdev-newspec -o libmad-0.15.1b.spec,会在当前目录下生成名为libmad-0.15.1b.spec的模板文件。
4、将libmad-0.15.1b.spec修改成如下的样子:5、在rpmbuild/SPECS目录下执行打包编译:
点击(此处)折叠或打开
因为我是64位系统,所以编译出的libmad适用于CentOS6.0-64。
如果我们将libmad的源码和spec文件拷贝32位系统上,再执行rpm打包,看看结果:点击(此处)折叠或打开
上一篇:Fedora 17下交叉编译vlc-2.0.6-win32小记
下一篇:Segmentation fault到底是何方妖孽
ghoulich2014-09-02 08:47:17
通过这种方式制作的RPM包,在使用rpm -ivh命令安装的时候,会向RPMDB中写入这个包的信息么?另外,依赖关系怎么解决呢?