成功最有效的方法就是向有经验的人学习!

制作一个简单的rpm包:helloworld

一. 简介

之前介绍yum是基于rpm的包管理工具,yum最终安装的是rpm包,那rpm包是如何来的呢?

按照网上的教程制作了个rpm包,这里记录下。

二. 过程

1)安装制作工具

yum -y install rpm-build rpm-devel rpmdevtools

2)生成开发目录

rpmdev-setuptree 

3)源代码
现在,我们来编码源代码,这里我们写个脚本,输出Hello World!

mkdir -p ~/rpmbuild/SOURCES/helloworld-1.0.0
cd ~/rpmbuild/SOURCES/helloworld-1.0.0
touch helloworld
chmod 755 helloworld
echo '#!/bin/sh' >> helloworld
echo 'echo Hello World!' >> helloworld
cd ~/rpmbuild/SOURCES
tar zcvf helloworld-1.0.0.tar.gz helloworld-1.0.0

这样我们就有了我们的源代码helloworld-1.0.0.tar.gz

4)编写spec文件

cd  ~/rpmbuild/SPECS
# 生成spec模版文件
rpmdev-newspec helloworld.spec

将内容修改为

Name:           helloworld
Version:        1.0.0
Release:        1%{?dist}
Summary:        helloworld

Group:          Development/Tools
License:        GPL
#URL:            
Source0:        %{name}-%{version}.tar.gz

#BuildRequires:  
#Requires:       

%description

%prep
%setup -q

%build

%install
mkdir -p $RPM_BUILD_ROOT/usr/bin
cp $RPM_BUILD_DIR/%{name}-%{version}/helloworld $RPM_BUILD_ROOT/usr/bin/

%clean
rm -rf $RPM_BUILD_ROOT

%files
%defattr(-,root,root,-)
%doc
/usr/bin/helloworld

%changelog

5)打包

rpmbuild -ba SPECS/helloworld.spec

查看下最后的目录结构

 tree ~/rpmbuild/
 /root/rpmbuild/
├── BUILD
│   └── helloworld-1.0.0
│       ├── debugfiles.list
│       ├── debuglinks.list
│       ├── debugsources.list
│       ├── elfbins.list
│       └── helloworld
├── BUILDROOT
├── RPMS
│   └── x86_64
│       ├── helloworld-1.0.0-1.el7.x86_64.rpm
│       └── helloworld-debuginfo-1.0.0-1.el7.x86_64.rpm
├── SOURCES
│   ├── helloworld-1.0.0
│   │   └── helloworld
│   └── helloworld-1.0.0.tar.gz
├── SPECS
│   └── helloworld.spec
└── SRPMS
    └── helloworld-1.0.0-1.el7.src.rpm

BUILD是编译rpm包的临时目录
BUILDROOT是最后生成rpm包的临时安装目录
RPMS存放最终生成的rpm二进制包
SOURCES是源代码(.tar.gz)存放目录
SPECS用来存放spec文件
SRPMS存放最终生成的rpm源码包
rpmbuild/RPMS/x86_64/helloworld-1.0.0-1.el7.x86_64.rpm就是我们打出来的rpm包


6)安装

yum install ~/rpmbuild/RPMS/x86_64/helloworld-1.0.0-1.el7.x86_64.rpm 

或者

rpm -ivh helloworld-1.0.0-1.el7.x86_64.rpm 

命令行运行

helloworld
Hello World!

好啦,成功了!

三. spec

好了,回过头再看看打包的步骤,最重要的莫过于helloworld.spec了,我们来详细解释下。

Name:           helloworld
Version:        1.0.0
Release:        1%{?dist}
Summary:        helloworld

Group:          Development/Tools
License:        GPL

名称、版本号、打包版本号、简介、Group、License

Source0:        %{name}-%{version}.tar.gz

源代码路径,要确保在SOURCES目录下能找到该包

#BuildRequires:  

编译需要的环境,如gcc>=4.7,这里不需要

#Requires:      

该软件运行的依赖,如python rpm>=0:4.1.1,这里不需要

%description

详细描述

%prep
%setup -q

编译前的准备操作在这儿,%setup macro 会把 source code tarball 解开并自动进到 %{name}-%{version} 的目录中

%build

编译,对应源代码打包的./configure和make,例如(%configure –prefix=%{_prefix})

%install
mkdir -p $RPM_BUILD_ROOT/usr/bin
cp $RPM_BUILD_DIR/%{name}-%{version}/helloworld $RPM_BUILD_ROOT/usr/bin/

安装,对应源代码包打包的make install,一般我们是安装在$RPM_BUILD_ROOT下

%files
%defattr(-,root,root,-)
%doc
/usr/bin/helloworld

收集文件并创建二进制和源RPM文件

%clean
rm -rf $RPM_BUILD_ROOT

删除临时构建目录

四. 一些变量

%{_bindir} /usr/bin/

MYSQL打包示例

1、把原码包mysql-5.7.17.tar.gz上传到SOURCES目录下,并在SPECS目录下添加配置好的mysql.spec文件:

由于在Mysql5.6后都要依赖boost_1_59_0.tar.gz包,所以这里我直接解压到BUILD目录下,不然检测不到;

tar xf boost_1_59_0.tar.gz -C rpmbuild/BUILD/

2、配置mysql.spec文件,还需要添加一个my.cnf配置文件到SOURCES目录下;

Name:       mysql 
Version:    5.7.17 
Release:    1%{?dist} 
License:    GPL 
URL:        http://downloads.mysql.com/archives/get/file/mysql-5.7.17.tar.gz 
Group:      applications/database 
Source:     mysql-5.7.17.tar.gz 
BuildRoot:  %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) 
BuildRequires:  cmake 
Packager:   hz328@qq.com 
Autoreq:    no 
#Source: %{name}-%{version}.tar.gz 
prefix: /usr/local/mysql-%{version} 
Summary: MySQL 5.7.17 

%description  
The MySQL(TM) software delivers a very fast, multi-threaded, multi-user, 
and robust SQL (Structured Query Language) database server. MySQL Server 
is intended for mission-critical, heavy-load production systems as well 
as for embedding into mass-deployed software. 

%define MYSQL_USER mysql 
%define MYSQL_GROUP mysql 

%prep 
%setup -n mysql-%{version} 


%build 

#CFLAGS="-O3 -g -fno-exceptions -static-libgcc -fno-omit-frame-pointer -fno-strict-aliasing" 
#CXX=g++ 
#CXXFLAGS="-O3 -g -fno-exceptions -fno-rtti -static-libgcc -fno-omit-frame-pointer -fno-strict-aliasing" 
#export CFLAGS CXX CXXFLAGS 

cmake \ 
-DCMAKE_INSTALL_PREFIX=%{prefix} \ 
-DMYSQL_DATADIR=/data \ 
-DWITH_BOOST=../boost_1_59_0 \ 
-DSYSCONFDIR=/etc \ 
-DWITH_MYISAM_STORAGE_ENGINE=1 \ 
-DWITH_INNOBASE_STORAGE_ENGINE=1 \ 
-DWITH_MEMORY_STORAGE_ENGINE=1 \ 
-DWITH_READLINE=1 \ 
-DMYSQL_UNIX_ADDR=/tmp/mysql.sock \ 
-DMYSQL_TCP_PORT=3306 \ 
-DENABLED_LOCAL_INFILE=1 \ 
-DWITH_PARTITION_STORAGE_ENGINE=1 \ 
-DEXTRA_CHARSETS=all \ 
-DDEFAULT_CHARSET=utf8 \ 
-DDEFAULT_COLLATION=utf8_general_ci 

make -j `cat /proc/cpuinfo | grep processor| wc -l` 

%install 
rm -rf %{buildroot} 
make install DESTDIR=%{buildroot} 
cp %{_sourcedir}/my.cnf $RPM_BUILD_ROOT%{prefix}/ 


%pre 
mkdir -p /data 
useradd -s /bin/nologin -M mysql >/dev/null 2>&1 

%post 
/bin/cp %{prefix}/support-files/mysql.server /etc/init.d/mysql 
/bin/cp %{prefix}/my.cnf %{_sysconfdir}/my.cnf 
chkconfig mysql on 
%{prefix}/bin/mysqld --initialize-insecure --basedir=%{prefix} --datadir=/data/mysql --user=mysql 
service mysql start 
chown -R mysql:mysql /data/mysql 
echo "export PATH=.:\$PATH:/usr/local/mysql-%{version}/bin;" >> ~/.bash_profile 
source ~/.bash_profile 

ln -s %{prefix}/lib %{prefix}/lib64 

%preun 
service mysql stop 
chkconfig --del mysql 
userdel -r mysql >/dev/null 2>&1 
rm -rf /usr/local/mysql-%{version} >/dev/null 2>&1 
rm -rf /data/mysql >/dev/null 2>&1 
rm -rf /etc/init.d/mysql >/dev/null 2>&1 

%files 
%defattr(-, %{MYSQL_USER}, %{MYSQL_GROUP}) 
%attr(755, %{MYSQL_USER}, %{MYSQL_GROUP}) %{prefix}/* 

%changelog

3、执行命令打包,需要一点时间看机器的配置;

rpmbuild -bb rpmbuild/SPECS/mysql-5.7.17-new.spec

4、完成后在rpmbuild/RPM目录下就会两个rpm包;

[root@rhce ~]# ll rpmbuild/RPMS/x86_64/
total 267280
-rw-r--r-- 1 root root  80603892 May 28 19:47 mysql-5.7.17-1.el6.x86_64.rpm
-rw-r--r-- 1 root root 193088996 May 28 19:48 mysql-debuginfo-5.7.17-1.el6.x86_64.rpm

5、直接安装,安装完成后会直接启动Mysql:

[root@rhce ~]# rpm -ivh rpmbuild/RPMS/x86_64/mysql-5.7.17-1.el6.x86_64.rpm  
Preparing...                ########################################### [100%] 
   1:mysql                  ########################################### [100%] 
Starting MySQL...[  OK  ]

不关闭服务直接卸载:

[root@rhce ~]# rpm -e --nodeps mysql-5.7.17-1.el6.x86_64

Shutting down MySQL..[  OK  ]

注意这里配置了,在卸载服务时会把mysql目录删除,所以要先备份数据;

配置文件主体介绍

spec脚本主体 
spec脚本的主体中也包括了很多关键字和描述,下面会一一列举。我会把一些特别需要留意的地方标注出来。
%prep 预处理脚本

%setup -n %{name}-%{version} 把源码包解压并放好
通常是从/usr/src/asianux/SOURCES里的包解压到/usr/src/asianux/BUILD/%{name}-%{version}中。
一般用%setup -c就可以了,但有两种情况:一就是同时编译多个源码包,二就是源码的tar包的名称与解压出来的目录不一致,此时,就需要使用-n参数指定一下了。

%patch 打补丁
通常补丁都会一起在源码tar.gz包中,或放到SOURCES目录下。一般参数为:
%patch -p1 使用前面定义的Patch补丁进行,-p1是忽略patch的第一层目录
%Patch2 -p1 -b xxx.patch 打上指定的补丁,-b是指生成备份文件

◎补充一下 
引用
%setup 不加任何选项,仅将软件包打开。 
%setup -n newdir 将软件包解压在newdir目录。 
%setup -c 解压缩之前先产生目录。 
%setup -b num 将第num个source文件解压缩。 
%setup -T 不使用default的解压缩操作。 
%setup -T -b 0 将第0个源代码文件解压缩。 
%setup -c -n newdir 指定目录名称newdir,并在此目录产生rpm套件。 
%patch 最简单的补丁方式,自动指定patch level。 
%patch 0 使用第0个补丁文件,相当于%patch ?p 0。 
%patch -s 不显示打补丁时的信息。 
%patch -T 将所有打补丁时产生的输出文件删除。


%configure 这个不是关键字,而是rpm定义的标准宏命令。意思是执行源代码的configure配置
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行 ,使用标准写法,会引用/usr/lib/rpm/marcros中定义的参数。
另一种不标准的写法是,可参考源码中的参数自定义,例如:
引用
CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix}

%build 开始构建包
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make的工作 ,常见写法:
引用
make %{?_smp_mflags} OPTIMIZE="%{optflags}"

都是一些优化参数,定义在/usr/lib/rpm/marcros中

%install 开始把软件安装到虚拟的根目录中
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make install的操作。这个很重要,因为如果这里的路径不对的话,则下面%file中寻找文件的时候就会失败。 常见内容有:
%makeinstall 这不是关键字,而是rpm定义的标准宏命令。也可以使用非标准写法:
引用
make DESTDIR=$RPM_BUILD_ROOT install

或
引用
make prefix=$RPM_BUILD_ROOT install

需要说明的是,这里的%install主要就是为了后面的%file服务的。所以,还可以使用常规的系统命令:
引用
install -d $RPM_BUILD_ROOT/
cp -a * $RPM_BUILD_ROOT/

%clean 清理临时文件
通常内容为:
引用
[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
rm -rf $RPM_BUILD_DIR/%{name}-%{version}

※注意区分$RPM_BUILD_ROOT和$RPM_BUILD_DIR:
$RPM_BUILD_ROOT是指开头定义的BuildRoot,而$RPM_BUILD_DIR通常就是指/usr/src/asianux/BUILD,其中,前面的才是%file需要的。 

%pre rpm安装前执行的脚本

%post rpm安装后执行的脚本

%preun rpm卸载前执行的脚本

%postun rpm卸载后执行的脚本

%preun %postun 的区别是什么呢?
前者在升级的时候会执行,后者在升级rpm包的时候不会执行

%files 定义那些文件或目录会放入rpm中
这里会在虚拟根目录下进行,千万不要写绝对路径,而应用宏或变量表示相对路径。 如果描述为目录,表示目录中除%exclude外的所有文件。
%defattr (-,root,root) 指定包装文件的属性,分别是(mode,owner,group),-表示默认值,对文本文件是0644,可执行文件是0755

%exclude 列出不想打包到rpm中的文件
※小心,如果%exclude指定的文件不存在,也会出错的。 
%changelog 变更日志

fpm快速制作rpm包

FPM功能简单说就是将一种类型的包转换成另一种类型。FPM是Ruby模块,其实打包时也是调用rpmbuild命令。

支持的源类型包:

  • dir 将目录打包成所需要的类型,可以用于源码编译安装的软件包
  • rpm 对rpm进行转换
  • gem 对rubygem包进行转换
  • python 将python模块打包成相应的类型

支持的目标类型包:

  • rpm 转换成rpm包
  • deb 转换成deb包
  • solaris 转换成solaris包
  • puppet 转换成puppet模块

安装FPM

  1. 安装依赖包
# yum -y install ruby rubygems ruby-devel gcc make
  1. 添加仓库
# gem sources -a http://mirrors.aliyun.com/rubygems/
  1. 移除原有的仓库
# gem sources --remove https://rubygems.org/
# gem sources --remove http://rubygems.org/
  1. 查看仓库是不是只有自己添加的那个仓库地址  
# gem sources -l
http://mirrors.aliyun.com/rubygems/
  1. 安装fpm  
# gem install fpm

如果遇到报错:

Building native extensions.  This could take a while...
ERROR:  Error installing fpm:
        ffi requires Ruby version >= 1.9.

原因:安装fpm需要依赖包ruby的版本在1.9以上,那么升级ruby就可以了。

解决:

1. 使用rvm安装,首先需要安装rvm
先查看你是否安装过rvm, 执行命令
rvm -v

2.yum -y update nss
   curl -L get.rvm.io | bash -s stable
执行成功后,根据尾部的提示执行:source /etc/profile.d/rvm.sh (路径以尾部提示为准)

3. 查看是否安装成功, 输入:rvm -v

4. 列表显示都可以安装ruby的哪些版本
rvm list known

5. 更新ruby至版本2.3.0
rvm install 2.3.0
  1. 如何查看fpm帮助  
# fpm --help  

常用参数:

  • -s 指定源类型
  • -t 指定目标类型
  • -n 指定包的名字
  • -v 指定包的版本号
  • -C 指定打包的相对路径 change directory to here before searching for files
  • -d 指定依赖于哪些包
  • -f 第二次打包时目录下如果有同名安装包存在,则覆盖它
  • -p 输出的安装包的目录,不想放在当前目录下就需要指定
  • –post-install 软件包安装完成之后所要运行的脚本,同–after-install
  • –pre-install 软件包安装完成之前所要运行的脚本,同–before-install
  • –post-uninstall 软件包卸载之后所要运行的脚本,同–after-install
  • –pre-uninstall 软件包卸载之前所要运行的脚本,同–before-install

打包示例

  1. 打包MySQL

事先安装好MySQL,MySQL安装过程这里不在详述。命令行终端输入以下命令,然后等待rpm包制作完成。

# fpm -s dir -t rpm -n mysql -v 5.6.27 --description 'author: jkzhao' -d 'libaio' -d 'libaio-devel' --pre-install /usr/local/mysql/mysql_pre_init.sh --post-install /usr/local/mysql/mysql_post_init.sh  /usr/local/mysql /usr/local/mysql-5.6.27-linux-glibc2.5-x86_64 /data

【注意】:默认打好的包是在当前目录下。

命令说明:

  • -s dir:指定源文件是目录的形式
  • -t rpm:指定打包的格式
  • -n:指定打包后名称
  • -v:版本号
  • –description:描述信息
  • -d:指定需要依赖的包。安装MySQL前需要在系统上安装libaio、libaio-devel。当你安装fpm打包成的rpm包时,它会先去检测系统上是否安装了这两个包,如果没有安装会给出提示,并终止rpm的安装。
  • –pre-install:安装rpm包前需要执行的脚本
  • –post-install:安装rpm包后需要执行的脚本

mysql_pre_init.sh的内容如下:

#!/bin/bash

user=mysql
group=mysql

# create group if not exists.
egrep "^$group" /etc/group >& /dev/null
if [ $? -ne 0 ]
then
    groupadd -r -g 300 $group
fi

# create user if not exists. 
egrep "^$user" /etc/passwd >& /dev/null
if [ $? -ne 0 ]
then
    useradd -g $group -r -s /sbin/nologin -u 300 $user
fi

mysql_post_init.sh的内容如下:

#!/bin/bash

# cp my.cnf force.
\cp /usr/local/mysql/my.cnf /etc/

# start/stop/restart script.
\cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chkconfig --add mysqld

# MySQL Client PATH.
\cp /usr/local/mysql/mysql.sh /etc/profile.d/

cd /usr/local/mysql
chown -R root.mysql .
chown -R mysql.mysql /data

打包完成后正常安装,如:  

# rpm -ivh mysql-5.6.27-1.x86_64.rpm
  1. 打包openresty  

事先安装好openresty。命令行终端输入以下命令,然后等待rpm包制作完成。

# fpm -s dir -t rpm -n openresty -v 1.9.7.3 --description 'author: jkzhao' -d 'openssl-devel' -d 'readline-devel' -d 'pcre-devel' -d 'gcc' --post-install /usr/local/openresty/openresty_init.sh  /usr/local/openresty

如果报如下错误:

Need executable 'rpmbuild' to convert dir to rpm {:level=>:error}

解决:

# yum install -y rpm-build

openresty_init.sh的内容如下:

#!/bin/bash

mv /usr/local/openresty/nginx.service /etc/systemd/system/
systemctl enable nginx.service

卸载安装后的rpm包

如果重新安装rpm,必须先卸载rpm包,然后删除相应的目录及文件,否则再次安装时会报错。
【注意】:卸载不要先直接删除目录和文件,否则你再次安装这个包时会说已安装,冲突了。

# rpm -e --nodeps  mysql-5.6.27-1.x86_64.rpm

然后再去删除各个目录和配置文件。 

赞(0) 打赏
未经允许不得转载:陈桂林博客 » 制作一个简单的rpm包:helloworld
分享到

大佬们的评论 抢沙发

全新“一站式”建站,高质量、高售后的一条龙服务

微信 抖音 支付宝 百度 头条 快手全平台打通信息流

橙子建站.极速智能建站8折购买虚拟主机

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

登录

找回密码

注册