RPM是RedHat Package Manager(RedHat软件包管理工具)的缩写,想要把源码包制作成rpm包,可以使用redhat官方提供的rpm-build工具 。不过rpmbuild制作的过程相对复杂,需要编写相对复杂的spec文件,这里还有非官方的工具推荐。如:fpm(基于ruby开发的)、checkinstall 。本篇着重介绍checkinstall ,其可以制deb、rpm等格式的包,在制作rpm包时,是基于rpmbuild做的二次开发,制作过程较rpmbuild方式简单很多。

一、checkinstall的安装

目前最新版本是1.6.2,可以按下面的方式下载安装。

1wget http://asic-linux.com.mx/~izto/checkinstall/files/source/checkinstall-1.6.2.tar.gz
2tar  zxvf checkinstall-1.6.2.tar.gz
3cd checkinstall-1.6.2
4make  && make install

不过我在centos6.5 X64上安装时,并不像上面写的那么简单就可以使用,在安装过程中可能会遇到如下的问题,需要解决。

问题1、make时msgfmt报错

报错内容为:

1/bin/sh: line 5: msgfmt: command not found
2make: *** [all] Error 1

这里可以通过安装gettext包解决:

1[root@localhost ~]# rpm -qf /usr/bin/msgfmt
2gettext-0.17-16.el6.x86_64

问题2、make时installwatch报错

报错内容如下:

 1[root@localhost checkinstall-1.6.2]# make
 2for file in locale/checkinstall-*.po ; do
 3                case ${file} in
 4                        locale/checkinstall-template.po)  ;;
 5                        *)
 6                                out=`echo $file | sed -s 's/po/mo/'` ;
 7                                msgfmt -o ${out} ${file} ;
 8                                if [ $? != 0 ] ; then
 9                                        exit 1 ;
10                                fi ;
11                        ;;
12                esac ;
13        done
14make -C installwatch
15make[1]: Entering directory `/usr/local/src/checkinstall-1.6.2/installwatch'
16gcc -Wall -c -D_GNU_SOURCE -DPIC -fPIC -D_REENTRANT -DVERSION="0.7.0beta7" installwatch.c
17installwatch.c:2942: error: conflicting types for ‘readlink’
18/usr/include/unistd.h:828: note: previous declaration of ‘readlink’ was here
19installwatch.c:3080: error: conflicting types for ‘scandir’
20/usr/include/dirent.h:252: note: previous declaration of ‘scandir’ was here
21make[1]: *** [installwatch.o] Error 1
22make[1]: Leaving directory `/usr/local/src/checkinstall-1.6.2/installwatch'
23make: *** [all] Error 2

出现该错误需要修改installwatch/installwatch.c文件,具体需要修改的部分如下:

将101行处修改

1static int (*true_scandir)( const char *,struct dirent ***,
2int (*)(const struct dirent *),
3int (*)(const void *,const void *));
4改为:
5static int (*true_scandir)( const char *,struct dirent ***,
6int (*)(const struct dirent *),
7int (*)(const struct dirent **,const struct dirent **));

将121行处修改:

1static int (*true_scandir64)( const char *,struct dirent64 ***,
2int (*)(const struct dirent64 *),
3int (*)(const void *,const void *));
4改为:
5static int (*true_scandir64)( const char *,struct dirent64 ***,
6int (*)(const struct dirent64 *),
7int (*)(const struct dirent64 **,const struct dirent64 **));

将2941行修改:

1#if (GLIBC_MINOR <= 4)
2改为
3#if (0)

将3080行修改:

1int scandir( const char *dir,struct dirent ***namelist,
2int (*select)(const struct dirent *),
3int (*compar)(const void *,const void *) ) {
4改为:
5int scandir( const char *dir,struct dirent ***namelist,
6int (*select)(const struct dirent *),
7int (*compar)(const struct dirent **,const struct dirent **) ) {

将3692行修改:

1int scandir64( const char *dir,struct dirent64 ***namelist,
2int (*select)(const struct dirent64 *),
3int (*compar)(const void *,const void *) ) {
4改为:
5int scandir64( const char *dir,struct dirent64 ***namelist,
6int (*select)(const struct dirent64 *),
7int (*compar)(const struct dirent64 **,const struct dirent64 **) ) {

完成后再进行make即可。

在ubuntu上安装时,由于可以直接使用apt进行安装,所以没有遇到上面所说的问题,在centos上遇到的问题参考了:http://www.patrickmin.com/linux/tip.php?name=checkinstall_fedora_13

问题3、rpmbuild报错

前面两个问题解决完成后,checkinstall看起来已经正常,不过在使用过程中还会遇到如下的报错。

1/root/rpmbuild has no SOURCES directory. Please write the path to
2the RPM source directory tree:

出现该问题的原因,是因为checkinstall还是需要rpmbuild做底层支撑,如果没有安装rpmbuild时,会出现上面的报错。解决方法如下:

1yum install gcc rpm-build pcre-devel rpmdevtools

安装完成后,需要再运行rpmdev-setuptree命令创建目录查看,具体如下:

1#rpmdev-setuptree
2#cd /root
3#tree -L 1 rpmbuild/
4rpmbuild/
5├── BUILD
6├── RPMS
7├── SOURCES
8├── SPECS
9└── SRPMS

问题4、ld.so报错

该出错是出现在x64系统下的,x86系统下没有该问题。此处的报错也是在checkinstall生成rpm包的过程中,报错内容为:

1ERROR: ld.so: object '/usr/local/lib64/installwatch.so' from LD_PRELOAD cannot be preloaded: ignored.

解决方法如下:

1[root@localhost ~]# echo "/usr/local/lib64" >/etc/ld.so.conf.d/installwatch.conf
2[root@localhost ~]# ln -s /usr/local/lib/installwatch.so /usr/local/lib64/installwatch.so
3[root@localhost ~]# ldconfig

二、checkinstall制作rpm包

这里以tengine为例,制作一个tengine的rpm包,具体步骤如下:

 1[root@localhost src]tar zxvf tengine-2.0.1.tar.gz
 2[root@localhost src]cd tengine-2.0.1
 3[root@localhost tengine-2.0.1]# ./configure --prefix=/usr/local --sbin-path=/usr/sbin/nginx
 4--conf-path=/etc/nginx/nginx.conf
 5--error-log-path=/var/log/nginx/error.log
 6--http-log-path=/var/log/nginx/access.log
 7--pid-path=/var/run/nginx.pid
 8--lock-path=/var/run/nginx.lock
 9--user=nginx --group=nginx
10--with-http_ssl_module --with-http_flv_module
11--with-http_stub_status_module
12--with-http_gzip_static_module
13--http-client-body-temp-path=/var/cache/nginx/client_temp
14--http-proxy-temp-path=/var/cache/nginx/proxy_temp
15--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp
16--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp
17--http-scgi-temp-path=/var/cache/nginx/scgi_temp
18--with-pcre --with-http_realip_module
19--with-http_addition_module
20--with-http_sub_module --with-http_dav_module
21--with-http_mp4_module --with-http_random_index_module
22--with-http_secure_link_module --with-file-aio --with-http_upstream_check_module
23--with-http_limit_conn_module=shared
24--with-http_limit_req_module=shared
25[root@localhost tengine-2.0.1]#make
26[root@localhost tengine-2.0.1]# checkinstall
27checkinstall 1.6.2, Copyright 2009 Felipe Eduardo Sanchez Diaz Duran
28           This software is released under the GNU GPL.
29The package documentation directory ./doc-pak does not exist.
30Should I create a default set of package docs?  [y]: y
31Preparing package documentation...OK
32Please choose the packaging method you want to use.
33Slackware [S], RPM [R] or Debian [D]? R
34Please write a description for the package.
35End your description with an empty line or EOF.
36>> tengine for 361way.com order by yang
37>>
38**************************************
39**** RPM package creation selected ***
40**************************************
41This package will be built according to these values:
421 -  Summary: [ tengine for 361way.com order by yang ]
432 -  Name:    [ tengine ]
443 -  Version: [ 2.0.1 ]
454 -  Release: [ 1 ]
465 -  License: [ GPL ]
476 -  Group:   [ Applications/System ]
487 -  Architecture: [ x86_64 ]
498 -  Source location: [ tengine-2.0.1 ]
509 -  Alternate source location: [  ]
5110 - Requires: [  ]
5211 - Provides: [ tengine ]
53Enter a number to change any of them or press ENTER to continue:
54Installing with make install...
55========================= Installation results ===========================
56make -f objs/Makefile install
57make[1]: Entering directory `/usr/local/src/tengine-2.0.1'
58test -d '/usr/local' || mkdir -p '/usr/local'
59……………………………………………………省略
60**********************************************************************
61 Done. The new package has been saved to
62 /root/rpmbuild/RPMS/x86_64/tengine-2.0.1-1.x86_64.rpm
63 You can install it in your system anytime using:
64      rpm -i tengine-2.0.1-1.x86_64.rpm
65**********************************************************************

完成后就可以取刚刚生成的rpm包到相同系统的主机上安装使用,安装前也可以通过以下命令查看详细的rpm包信息:

 1[root@kvm ~]# rpm -qpi tengine-2.0.1-1.x86_64.rpm
 2Name        : tengine                      Relocations: (not relocatable)
 3Version     : 2.0.1                             Vendor: (none)
 4Release     : 1                             Build Date: Tue 06 May 2014 10:39:02 AM CST
 5Install Date: (not installed)               Build Host: localhost
 6Group       : Applications/System           Source RPM: tengine-2.0.1-1.src.rpm
 7Size        : 2345906                          License: GPL
 8Signature   : (none)
 9Packager    : checkinstall-1.6.2
10Summary     : tengine for 361way.com order by yang
11Description :
12tengine for 361way.com order by yang

注:此时的rpm包在其他主机上通过rpm -i 安装使用时可能会遇到错误,因为在编译的时候我们自定义了很多参数。例出上面的tengine rpm 在使用时就会报错如下:

1#nginx
2nginx: [emerg] getpwnam("nginx") failed

报错原因很简单,因为我们编译的时候使用了–user=nginx –group=nginx 参数,而在新的主机上因为不存在该用户所以会报错 。如果想完会解决此类问题,可以在编译前修改下install文件或make文件,将新建用户,新建一些自定义目录都添加下,再编译生成rpm包就OK了。