最近学习rpm打包,参考ibm文档库里rpm打包的文章,结合自己的实践,总结如下,一来备忘,二来和大家交流。
和deb打包不同,rpm打包需要特定的目录及结构。查看rpm打包目录,以下为在CentOS5.5下的输出结果:
$rpm--showrc|grep_topdir
-14:_builddir%{_topdir}/BUILD
-14:_rpmdir%{_topdir}/RPMS
-14:_sourcedir%{_topdir}/SOURCES
-14:_specdir%{_topdir}/SPECS
-14:_srcrpmdir%{_topdir}/SRPMS
-14:_topdir%{_usrsrc}/redhat
$rpm--showrc|grep_usrsrc
-14:_topdir%{_usrsrc}/redhat
-14:_usrsrc%{_usr}/src
$rpm--showrc|grep_usr
-14:_defaultdocdir%{_usr}/share/doc
-14:_topdir%{_usrsrc}/redhat
-14:_usr/usr
-14:_usrsrc%{_usr}/src
经过层层寻找,最终发现打包目录在/usr/src/redhat目录下,看看目录结构:
$tree/usr/src/redhat
/usr/src/redhat
|--BUILD
|--RPMS
||--athlon
||--geode
||--i386
||--i486
||--i586
||--i686
|`--noarch
|--SOURCES
|--SPECS
`--SRPMS
其中BUILD存放编译生成的临时文件,RPMS存放根据各种构架生成的rpm包,SOURCES存放源码包,SPECS存放spec文件,SRPMS存放生成的SRPM
包。
最简单例子
下面以helloworld为例,构建一个最小化打包过程。
首先需要写一个SPEC文件:
Summary:helloworldrpmpackage
Name:hello
Version:0.1
Relea:1
Source:
Licen:GPL
Packager:amoblin
Group:Application
URL:
%description
Thisisasoftwareformakingyourlifemorebeautiful!
%prep
%tup-q
%build
gcc-ohellohello.c
%install
install-m755hello/usr/local/bin/hello
%files
/usr/local/bin/hello
放到上述SPECS目录下。
然后一个源程序hello.c:
#include
intmain()
{
printf("Hello,World!n");
return0;
}
存放在hello-0.1目录,然后打包放到SOURCES目录:
$o-0.1
hello-0.1/
hello-0.1/hello.c
$/usr/src/redhat/SOURCES
在SPECS目录下使用rpmbuild进行打包:
$cd/usr/src/redhat
$
...
Wrote:/usr/src/redhat/SRPMS/
Wrote:/usr/src/redhat/RPMS/i386/
这时会逐个运行文件的内容,最终生成两个文件,一个包含源码的rpm包和一个二进制rpm包。
使用-bs选项只生成源码rpm包;使用-bb选项只生成rpm包。
查看rpm包信息和包内容:
$rpm-qpi../RPMS/i386/
$rpm-qpl../RPMS/i386/
第一个命令的输出是spec文件的序言部分的内容,第二个命令的输出是%files部分的文件列表。
现在有个问题,打包目录在/usr/src/redhat下,需要root权限才能操作,太不方便了,能不能在用户自定义目录下打包呢?
自定义打包目录
我们可以通过修改topdir宏的值来自定义打包路径:
$echo%_topdir$HOME/rpmbuild>~/.rpmmacros
这样再查看topdir的值会发现已变为用户主目录下rpm子目录了。这时修改文件就方便多了。
但在执行rpmbuild时仍会出问题:
$
...
install:无法删除“/usr/local/bin/hello”:权限不够
error:Badexitstatusfrom/var/tmp/rpm-tmp.65773(%install)
...
这是因为rpmbuild在构建rpm包时会将程序安装一遍,然后再提取安装文件。由于需要复制二进制文件hello到系统目录/usr/local/bin/下,所
以普通用户执行就报错了。
那么怎么办呢?这里需要使用虚拟根了。
修改spec文件,在Description段落前,URL字段之后增加一行:
BuildRoot:%{_builddir}/%{name}-root
修改install段落,将绝对安装路径改为使用构建根的方式::
%install
mkdir-p$RPM_BUILD_ROOT/usr/local/bin
install-m755hello$RPM_BUILD_ROOT/usr/local/bin/hello
通过BuildRoot的值告诉rpmbuild,我们的构建根是builddir下的hello-root目录。其中以%{}括起来的是RPM宏,_builddir代表~/rpmbuild/BUILD
目录;name代表spec文件开头的Name字段值。
以下划线开头的builddir是系统RPM宏,我们可以通过rpm–showrc看到,可以在.rpmmacros中自定义。
RPM_BUILD_ROOT和前面的宏不同,这里没有{}括起来,是为了在以后安装生成的rpm时不至于也去寻找传说中的构建根。
如果喜欢的话,可以修改Source字段如下::
Source:%{name}-%{version}.
好,继续回到构建根。现在执行rpmbuild,会在BUILD下创建hello-root目录作为虚拟根,hello安装在其中的usr/local/bin目录下。
使用Makefile
一般源程序都使用Makefile的,因此我们再进一步,添加一个Makefile文件,在spec里使用make来编译。
简单的Makefile文件如下:
SRC=hello.c
hello:$(SRC)
gcc$^-o$@
clean:
rm-fhello
install:
-mkdir-p$(RPM_INSTALL_ROOT)/usr/local/bin/
install-m755hello$(RPM_INSTALL_ROOT)/usr/local/bin/hello
由于使用了Makefile,我们最好升级一下版本号,将原先的hello-0.1目录复制为hello-0.2目录,放入Makefile文件。
修改spec文件,更新版本号,同时将build和install部分用make替换::
Version:0.2
...
%build
make
%install
RPM_INSTALL_ROOT=$RPM_BUILD_ROOTmakeinstall
...
这里将构建根参数传递给Makefile,从而将程序安装在指定的根目录下。
如果喜欢做事不留痕的话,可以在install段落后面增加clean段,清理生成的虚拟根:
%clean
rm-rf$RPM_BUILD_ROOT
使用补丁文件
有很多源码包里都有补丁文件,在打包时要先打补丁,这也要在spec文件里告诉rpmbuild一声才行。
复制hello-0.2一份,随便修改一个hello.c,和原目录做比较,生成补丁文件:
$
$/hello.c
$diff-uNrhello-0.1hello-0.2>
然后修改spec文件,增加Patch字段,以及在prep段落增加打补丁动作::
...
Patch0:%{name}-%{version}.patch
...
%prep
%tup-q
%patch-p1
...
Patch0告诉rpmbuild这是一个补丁,如果补丁不止一个的话,可以通过Patch1,Patch2增加。
再次执行rpmbuild,生成rpm包。
查看SRPM包内容:
$rpm-qpl../SRPMS/
补丁果然被打包进来了!
在安装过程中使用脚本
可以使用%pre,%post,%preun,%postun段落来定义安装前后,卸载前后的脚本动作::
%pre
echoThisisprefor%{version}-%{relea}:arg=$1
%post
echoThisispostfor%{version}-%{relea}:arg=$1
%preun
echoThisispreunfor%{version}-%{relea}:arg=$1
%postun
echoThisispostunfor%{version}-%{relea}:arg=$1
具体的脚本内容可自行替换。
打包rpm的过程就这么简单!
但上面这些方法一般都是针对打包者的,打包者不管以什么手段从任何地方得到了源代码包,然后保持一颗虔诚的心,恭恭敬敬地将之安放在
rpmbuild/SOURCES目录下,然后天马行空,随意发挥或挥发,写下一篇洋洋洒洒的spec文件,对号入座到SPECS目录下,然后rpmbuild隆重出场,
进行一系列生产加工,最终产生出来了传说中的rpm包和包。
但,有时我们不总是打包者,更多时候我们是开发者,使用某种版本控制系统,比如Git,进行开发,最后的产品希望打包发布,还用上面的方式
吗?不行,太麻烦了~
那怎么办呢?欲知结果,敬请期待,清明之后见分晓~
在源代码中打包
仍拿前面的helloworld举例,把spec文件放到开发目录下,修改去掉补丁文件,然后打包:
$lshello-0.2
kefile
$o-0.2
hello-0.2/
hello-0.2/Makefile
hello-0.2/
hello-0.2/hello.c
接下来就要用到rpmbuild另一个很有用的参数了:-t,可以看一个rpmbuild的man:
$manrpmbuild
NAME
rpmbuild-BuildRPMPackage(s)
SYNOPSIS
BUILDINGPACKAGES:
rpmbuild{-ba|-bb|-bp|-bc|-bi|-bl|-bs}[rpmbuild-options]SPECFILE...
rpmbuild{-ta|-tb|-tp|-tc|-ti|-tl|-ts}[rpmbuild-options]TARBALL...
rpmbuild{--rebuild|--recompile}SOURCEPKG...
MISCELLANEOUS:
rpmbuild--showrc
...
rpmbuild通过-t参数来构建打包过的源程序。-ta就是构建rpm包和srpm包,-tb就是只构建二进制rpm包,-tp是只构建打过补丁的包,-ts是
只构建srpm包。
好了,现在可以生成rpm包了:
$
如果使用git的话,就更方便了,因为Git提供了对任意分支打包的命令:git-archive。下面我们先使用git初始化我们的开发目录,然后使用
git-archive来生成压缩包。
$cdhello-0.2
$gitinit
InitializedemptyGitrepositoryin/home/admin/work/hello-0.2/.git/
$gitadd-A
$gitci-minit
3fileschanged,73inrtions(+),0deletions(-)
createmode100644Makefile
createmode100644hello.c
$gitarchive--prefix=hello-0.2/master|gzip>
$ls
kefile
通过–prefix参数使当前master分支下文件打包到hello-0.2目录下,注意在文件夹名后面一定要有一个斜扛,否则就变成一般的文件名前缀了。
生成压缩包以后,就可以像之前一样使用rpmbuild来生成rpm包了。
使用这种方式编译rpm包,无疑给开发者带来了很多方便,尤其是使用git做版本控制的开发者。而且也比debian打包简单,debian打包需要一
个debian目录,里面一大堆文件,而rpm打包,一切尽在一个spec文件中,经典!
接下来说说python程序包的制作,这个比较特殊。
python应用程序的RPM包制作
正如前面所见的,rpmbuild内置了很多宏,使得在写rpm包时方便很多。所有这些宏都在/usr/lib/rpm/macros中定义。
查看python相关的宏:
$cat/usr/lib/rpm/macros|greppython
%__python/usr/bin/python
%__python_provides/usr/lib/rpm/--provides
%__python_requires/usr/lib/rpm/--requires
#atthepythonpromptforexample,after"importrpm".
如上,在spec文件里可以使用%{__python}来调用系统python。
这里没有定义sitelib,我们一般在spec文件开头自定义:
%{!?python_sitelib:%definepython_sitelib%(%{__python}-c"figimportget_python_lib;print
get_python_lib()")}
可以看出,%()里面是shell命令,通过python的get_python_lib函数得到python的sitelib路径。
此外,还有安装要求:
BuildRequires:python-devel
%if0%{?fedora}>=8
BuildRequires:python-tuptools-devel
%el
BuildRequires:python-tuptools
%endif
在安装部分,可以使用%{__python}宏来进行安装:
%install
rm-rf$RPM_BUILD_ROOT
%{__python}all--root$RPM_BUILD_ROOT
–root$RPM_BUILD_ROOT的作用就是告诉安装到虚拟根上,类似前面的RPM_INSTALL_ROOT=$RPM_BUILD_ROOT。
此外,这里还有一个INSTALLED_FILES标志可以使用,用来标记安装到系统中的文件,但来自fedoraproject的建议是,不提倡使用
INSTALLED_FILES,因为它只会标记文件,而不会标记目录,所以有可能遗漏。
打包文件列表部分写法如下:
%files
%defattr(-,root,root,-)
%attr(755,root,root)%{_bindir}/gistore
%{python_sitelib}/*
%doc/usr/share/doc/gistore/README
%doc/usr/share/doc/gistore/COPYING
%doc/usr/share/doc/gistore/CHANGELOG
%files部分列出要打包的文件和目录,可以使用前面的标记安装文件,但最好的方法就是把文件或目录手动列出来。
%defattr(-,root,root,-)代表使用默认的文件和目录权限
%{_bindir}是系统bin目录,具体为/usr/bin/,这个目录下的文件一般是可执行的。
%doc代表文档,可以这样写::
%docREADMECOPYINGCHANGELOG
这样的话,rpmbuild会从源码根目录下复制上述文件到/usr/share/doc/%{name}-%{version}/目录下,而按照前面的那种三行的写法的话,是自定
义doc文件夹的位置,可以看出,自定义的doc文件夹名称没有版本号。
写完了以后就可以打包了,打包过程和前面无异。
下次有时间的话,会讲如何进行多个子包的打包~
本文发布于:2022-11-23 08:12:33,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/4623.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |