原文地址:一堂课玩转rpm包的制作 作者:wjlkoorey258
常见的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 |
rpmbuild -bb 软件名-版本.spec
[root@localhost ~]# rpmdev-newspec -o myapp-0.1.0.spec
Skeleton specfile (minimal) has been created to "myapp-0.1.0.spec".
[root@localhost ~]# cat myapp-0.1.0.spec
Name: myapp-0.1.0
Version:
Release: 1%{ ?dist}
Summary:
Group:
License:
URL:
Source0:
BuildRoot: %{_tmppath}/%{ name}-%{ version}-%{ release}-root-%(%{ __id_u} -n)
BuildRequires:
Requires:
%description
%prep
%setup -q
%build
%configure
make %{ ?_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
%doc
%changelog
Name: myapp <===软件包的名字(后面会用到)
Version: 0.1.0 <===软件包的版本(后面会用到)
Release: 1%{?dist} <===发布序号
Summary: my first rpm <===软件包的摘要信息
Group: <===软件包的安装分类,参见/usr/share/doc/rpm-4.x.x/GROUPS这个文件
License: GPL <===软件的授权方式
URL: <===这里本来写源码包的下载路径或者自己的博客地址或者公司网址之类
Source0: %{name}-%{version}.tar.gz <===源代码包的名称(默认时rpmbuid回到SOURCES目录中去找),这里的name和version就是前两行定义的值。如果有其他配 置或脚本则依次用Source1、Source2等等往后增加即可。
BuildRoot: %{_topdir}/BUILDROOT <=== 这是make install时使用的“虚拟”根目录,最终制作rpm安装包的文件就来自这里。
BuildRequires: <=== 在本机编译rpm包时需要的辅助工具,以逗号分隔。假如,要求编译myapp时,gcc的版本至少为4.4.2,则可以写成gcc >=4.2.2。还有其他依赖的话则以逗号分别继续写道后面。
Requires: <=== 编译好的rpm软件在其他机器上安装时,需要依赖的其他软件包,也以逗号分隔,有版本需求的可以
%description <=== 软件包的详细说明信息,但最多只能有80个英文字符。
阶段 | 动作 |
%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目录等 |
每个阶段的详细说明如下:
%prep阶段
%setup -q
%build阶段
%configure
make %{?_smp_mflags}
它就自动将软件安装时的路径自动设置成如下约定:
可执行程序/usr/bin
依赖的动态库/usr/lib或者/usr/lib64视操作系统版本而定。
二次开发的头文件/usr/include
文档及手册/usr/share/man
注意,这里的%configure是个宏常量,会自动将prefix设置成/usr。另外,这个宏还可以接受额外的参数,如果某些软件有某些高级特性需要开启,可以通过给%configure宏传参数来开启。如果不用 %configure这个宏的话,就需要完全手动指定configure时的配置参数了。同样地,我们也可以给make传递额外的参数,例如:
make %{?_smp_mflags} CFLAGS="" …
%install阶段
这个阶段就是执行make install操作。这个阶段会在%_buildrootdir目录里建好目录结构,然后将需要打包到rpm软件包里的文件从%_builddir里拷贝到%_buildrootdir里对应的目录里。这个阶段最常见的两条指令是:
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
%clean阶段
编译完成后一些清理工作,主要包括对%{buildroot}目录的清空(当然这不是必须的),通常执行诸如make clean之类的命令。
制作rpm软件包的阶段
%files
%defattr(-,root,root,-)
%doc
在%files阶段的第一条命令的语法是:
%defattr(文件权限,用户名,组名,目录权限)
如果不牵扯到文件、目录权限的改变则一般用%defattr(-,root,root,-)这条指令来为其设置缺省权限。所有需要打包到rpm包的文件和目录都在这个地方列出,例如:
%files
%{_bindir}/*
%{_libdir}/*
%config(noreplace) %{_sysconfdir}/*.conf
%exclude dic_name或者file_name
但是关于%files阶段有两个特性要牢记:
%{buildroot}里的所有文件都要明确被指定是否要被打包到rpm里。什么意思呢?假如,%{buildroot}目录下有4个目录a、b、c和d,在%files里仅指定a和b要打包到rpm里,如果不把c和d用exclude声明是要报错的;
如果声明了%{buildroot}里不存在的文件或者目录也会报错。
关于%doc宏,所有跟在这个宏后面的文件都来自%{_builddir}目录,当用户安装rpm时,由这个宏所指定的文件都会安装到/usr/share/doc/name-version/目录里。
%changelog阶段
* date +"%a %b %d %Y" 修改人 邮箱 本次版本x.y.z-p
- 本次变更修改了那些内容
说了这么多,我们实战一下。网上很多教程都是拿Tomcat或者Nigix开头,这里我就先从简单的mp3解码库libmad入手,将它打成一个rpm包,具体步骤如下:
(如果自己系统上没有rpmbuild命令就安装之:yum install rpm* rpm-build rpmdev*)
1、构建rpm的编译目录结构: 2 、下载 libmad 源码到 rpmbuild/SOURCES 目录下, 可以从 这里下载。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目录下执行打包编译:
rpmbuild -bb libmad-0.15.1b.spec
因为我是64位系统,所以编译出的libmad适用于CentOS6.0-64。
如果我们将libmad的源码和spec文件拷贝32位系统上,再执行rpm打包,看看结果: 结果如下: 后记: 关于SPEC文件,还有一些其他特性,诸如安装软件包之前、之后要做的事情,以及卸载软件包之前之后要做的事情,包括给源码打补丁,关于这些特性感兴趣的童鞋自己去摸索吧。最后给出一个完整的,包含了打补丁、安装、卸载特性的SPEC文件模板:
Name: test
Version:
Requires:
%description
…
#==================================SPEC头部====================================
%prep
%setup -q
%patch <==== 在这里打包
%build
%configure
make %{?_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root,-)
要打包到rpm包里的文件清单
%doc
%changelog
#==================================SPEC主体====================================
%pre
安装或者升级软件前要做的事情,比如停止服务、备份相关文件等都在这里做。
%post
安装或者升级完成后要做的事情,比如执行ldconfig重构动态库缓存、启动服务等。
%preun
卸载软件前要做的事情,比如停止相关服务、关闭进程等。
%postun
卸载软件之后要做的事情,比如删除备份、配置文件等。