如何无网络下免编译的安装程序(RPM包)

摘要:rpm包是预先在Linux主机上编译好并打包的文件,安装起来非常快捷。不需要再进行繁琐的编译等操作,拿来就能用,区别于yum包管理,rpm可以在不需要网络环境的情况下使用。学习完大神的文章还是有一些细节不太清楚,下面我就再对编译RPM包的过程和详细知识点再梳理扩展一下留作备忘。

简介

redhat包管理器rpm(redhat package manager),因为非常的方便,所以这个方式被广泛的使用现在rpm的英文翻译是一种递归写法(RPM package manager)。RPM是以一种数据库记录的方式来将所需要的套件安装在Linux主机的一套管理程序。也就是说Linux系统中存在一个关于rpm的数据库,它记录了安装的包与包之间的依赖相关性。我们可以在有网的环境下载rpm包,也可以定制化的将自己的软件打成rpm包。

准备rpm打包环境

我这里用的操作系统是CentOS6.7,redhat系的其它发行版应该也类似。

安装rpm-build

1
sudo yum install -y gcc make rpm-build redhat-rpm-config vim lrzsz

在无网络的机器上装备环境

需要在无网络的情况下解决一些依赖包的环境可以使用以下命令提前在一台有网络的机器上下载好RPM包再到无网络的机器上安装就可以了

1
yum install --downloadonly --downloaddir=<目录>  <packages>

创建必须的文件夹和文件

1
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}echo '%\_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros
文件名类型说明
SPECS目录包含rpm的xxx.spec文件(打包的描述文件)
SOURCES目录包含源码包(如.tar包)和所有patch补丁、service启动文件等
BUILD目录源码包被解压至此, 并在该目录的子目录完成编译
BUILDROOT目录存放编译后的文件的临时目录(保存%install阶段安装的文件)
RPMS目录经过编译成功后, 打包文件放在这个目录, 包含i386、i686、noarch等次级目录
SRPMS目录包含.src.rpm的SPRM包(通常用于审核和升级软件包)

制作spec文件

找spec模板文件

一般找一个类似的rpm源码包,将其安装,然后参照它写自己软件包的spec文件。

1
2
3
4
mkdir ~/rpms
wget -O ~/rpms/python-2.6.6-64.el6.src.rpm http://vault.centos.org/6.7/os/Source/SPackages/python-2.6.6-64.el6.src.rpm
rpm -ivh ~/rpms/python-2.6.6-64.el6.src.rpm
vim ~/rpmbuild/SPECS/python.spec # 参照这个文件来写自己软件包的spec文件

rpmbuild内置变量

rpmbuild --showrc可查看内置的变量

常用的几个变量:

1
2
3
4
5
6
7
8
9
$RPM_BUILD_DIR /$HOME/rpmbuild/BUILD
$RPM_BUILD_ROOT /$HOME/rpmbuild/BUILDROOT
%{_sysconfigdir} /etc
%{_sbindir} /usr/sbin
%{_bindir} /usr/bin
%{_prefix} /usr
%{_localstatedir} /var

更多的可以查看 --showrc

rpmbuild spec规范说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Summary: 软件包的内容概要描述
Name: 软件包的名称(spec文件名与其一致)
Version: 软件的实际版本号,具体和源码包一致
Release: 软件包的发布实际版本号
Url: 软件的主页
License: 软件授权方式(GPL等)
Group: 软件分组,如(Application/System)
Source: 软件的来源
Patch: 补丁patch file依赖的软件,安装的时候需要检查的
BuildRoot: 安装或者编译时使用的"虚拟目录",一般默认
BuildRequires: 编译过程中需要的软件
Requires: 依赖的软件, 安装的时候需要检查的
Packager: 软件的打包者
Vendor: 软件发行商或者打包组织信息,如(Apache Software Foundation)

%description: 软件包描述
%prep: 编译前预处理。如: 1.打补丁; 2. 解压源码等
%setup: 解压源码(一般是位于%prep下的macro, 自动解压源码)
%build: 编译
%install: 安装, 即把一些可执行文件和配置复制到目标目录中。
%clean: 清理一些暂存文件
%files: 定义哪些文件或者目录会放入rpm中
%pre: rpm安装前执行的动作
%post: rpm安装后执行的动作
%preun: 卸载前执行脚本程序(preun)开始执行
%postun: 卸载后执行脚本程序(postun)开始执行

更多参考: How_to_create_an_RPM_package

rpmbuild spec 示例

示例1 openstack-aodh.spec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
%global pypi_name aodh
%{!?upstream_version: %global upstream_version %{version}%{?milestone}}
Name: openstack-aodh
Version: 2.0.0
Release: %{es_versions}%{?dist}
Summary: OpenStack Telemetry Alarming
License: ASL 2.0
URL: https://github.com/openstack/aodh.git
BuildArch: noarch
Source0: http://tarballs.openstack.org/%{pypi_name}/%{pypi_name}-%{version}.tar.gz

...
%description
Aodh is the alarm engine of the Ceilometer project.

%prep
%setup -q -n %{pypi_name}-%{upstream_version}

%build
%{__python2} setup.py build

%install
%{__python2} setup.py install --skip-buid --root %{buildroot}

%files -n python-aodh
%{python2_sitelib}/aodh
...
%files common
%doc README.rst
%dir %{_sysconfdir}/aodh
%attr(-, root, aodh) %{_datadir}/aodh/aodh-dist.conf
%config(noreplace) %attr(-, root, aodh) %{_sysconfdir}/aodh/aodh.conf
...
%changelog

示例2 mariadb.spec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
%define debug_package %{nil}
%define install_dir /usr/local/mariadb

Name: mariadb
Version: 10.1.20
Release: 1%{?dist}
Summary: Mariadb client programs and shared libraries and server programs

Group: Applications/Databases
License: GPLv2 with exceptions
URL: https://mariadb.org/
Source0: mariadb-10.1.20.tar.gz

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
BuildRequires: readline-devel, openssl-devel
BuildRequires: gcc-c++, ncurses-devel, zlib-devel
BuildRequires: libtool, automake, autoconf, gawk
Requires: grep, automake, autoconf, bash
Autoreq: 0

%description
MariaDB Server is one of the most popular database servers in the world. It’s made by the original developers of MySQL and guaranteed to stay open source. Notable users include Wikipedia, WordPress.com and Google.


%prep
%setup -q

%build
cmake . -DMYSQL_UNIX_ADDR=/tmp/mariadb.sock \
-DEXTRA_CHARSETS=all \
-DMYSQL_USER=mysql \
-DCMAKE_INSTALL_PREFIX=%{install_dir} \
-DMYSQL_DATADIR=/data/mariadb \
-DWITH_XTRADB_STORAGE_ENGINE=1 \
-DWITH_FEDERATEDX_STORAGE_ENGINE=1 \
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_ARCHIVE_STPRAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_SSL=system \
-DVITH_ZLIB=system \
-DWITH_LOBWRAP=0 \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DENABLED_LOCAL_INFILE=ON \
-DWITH_PARTITION_STORAGE_ENGINE=1 \
-DWITH_PERFSCHEMA_STORAGE_ENGINE=1 \
-DWITH_READLINE=ON \
-DWITH_WSREP=ON \
-DWITH_INNODB_DISALLOW_WRITES=ON \
-DWITH_TOKUDB=1 \
-DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++ \
-DCMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc \
-DCMAKE_BUILD_TYPE:STRING=RELEASE
make %{?_smp_mflags}


%install
rm -rf %{buildroot}
make install DESTDIR=%{buildroot}

%pre
groupadd -r mysql 2> /dev/null
useradd -g mysql -r -M -s /sbin/nologin mysql 2> /dev/null
mkdir -p /data/mariadb/data 2> /dev/null
mkdir -p /data/mariadb/binlog 2> /dev/null
mkdir -p /data/mariadb/undolog 2> /dev/null
mkdir -p /var/run/mariadb/ 2> /dev/null
mkdir -p /var/log/mariadb/ 2> /dev/null
chown -R mysql.mysql /var/run/mariadb/ 2> /dev/null
chown -R mysql.mysql /var/log/mariadb/ 2> /dev/null
chown -R mysql.mysql /data/mariadb 2> /dev/null

%clean
rm -rf %{buildroot}

%files
%defattr(-, root, root, 0755)
%{install_dir}/
%doc

%changelog

spec更加详细内容见 这里

制作rpm包

上传必要的source文件

1
cp ${some_where}/Python-2.7.10.tgz ~/rpmbuild/SOURCES/

开始制作

1
2
cd ~/rpmbuild
rpmbuild -bb --target x86_64 SPECS/python27-tstack.spec > rpmbuild.log &

一切顺利的话,最终会在~/rpmbuild/RPMS/x86_64/目录下找到编译好的rpm包。

技巧总结

  • 不打debug的rpm包:在spec文件中加入%debug\_package %{nil}即可
  • 禁止自动分析源码添加不应该加入的依赖 在spec文件中加入Autoreq: 0即可
  • sepc文件中一些宏的用法 在spec文件中经常出现一些宏,比如%setup%patch,这两个宏的选项较多,使用时要特别注意,参见这里
  • 安装卸载rpm包前后的动作 可以通过%pre, %post, %preun, %postun指定rpm包在安装卸载前后的动作,比如在安装前用脚本做一些准备、在安装后用脚本做一些初始化动作、在卸载前用脚本做一些准备、在卸载后用脚本做一些清理动作

rpmbuild命令的选项 rpmbuild命令有不少选项,参见这里,用得比较多的有:

1
2
3
4
5
6
7
-bp 只解压源码及应用补丁
-bc 只进行编译
-bi 只进行安装到%{buildroot}
-bb 只生成二进制rpm包
-bs 只生成源码rpm包
-ba 生成二进制rpm包和源码rpm包
--target 指定生成rpm包的平台,默认会生成i686和x86_64的rpm包,但一般我只需要x86_64的rpm包

RPM 常用参数备忘

1
2
3
4
5
6
7
8
9
10
11
12
rpm -ivh ***.rpm: 安装软件(并且显示安装进度 --install--verbose--hash)
rpm -Uvh ***.rpm: 升级软件(--Update)
rpm -e: 卸载软件
rpm -q [软件名称]: 查询程序是否安装
rpm -qa: 查询已经安装的所有软件(Query All)
rpm -qi [软件名称]: 列出该软件的详细信息
rpm -qf [指定文件名]: 查找指定文件属于哪个RPM软件包(Query Files)
rpm -qc [软件名称]: 列出该软件的所有文件
rpm -qpi [软件名称]: 列出RPM软件包的描述信息(Query Packages install package(s))
rpm -qpl [软件名称]: 列出该软件的所有文件(Query Packages list)
rpm -qRp [软件名称]: 列出该软件的依赖(Query Rely Packages)
rpm -Va [软件名称]: 校验所有的RPM软件包,查找丢失的文件(View List)

其他

如何从python源码包构建rpm

在python源码目录执行

1
python setup.py bdist_rpm # 即可在当前dist目录下生成rpm包

定制spec:

1
2
3
python setup.py bdist_rpm --spec-only # 只生成dist/<module>.spec
# 重新编辑 dist/<module>.spec
python setup.py bdist_rpm --spec-file=dist/<module>.spec

无污染地打rpm包

方法一、使用mock来进程打包,详细的过程可以见

centos下无污染地打rpm包

mock编包一般是做发行版本给别人使用,当然你做的软件要能在别人机器上跑,那么在开发过程中,我们必须模拟一个纯净的用户环境(即是所谓的chroot),mock在编包前先构建一个这样的用户环境,然后里面再使用rpmbuild的机制编包。

总结来说,rpmbuild编出来的包是特例,而mock编出来包在具有共性。mock相当于给rpmbuild增加了一个外壳,包装了一下。

方法二、虚拟机操作

建议使用虚拟机操作,不要在自己的电脑上进行这些操作,不然到时候弄一大堆的包在自己电脑上很头疼的,如果没有虚拟机可以使用 vagrant在本地虚拟化出一个os进行操作 具体用法使用 Vagrant 打造跨平台开发环境

1
2
3
4
5
6
7
8
9
mkdir some-dir

cd some-dir

vagrant init centos/6

vagrant up

vagrant ssh

这两种方法各有各的好处,mock感觉有点像dock,只要编译完成后直接删除该mock环境就行,更加的纯洁迅速; 而Vagrant如果没有理解错他就是在本地安装了一个虚拟机,比起mock更重一些,但是可以比较轻松的应对更多的场景,比如说在本地开发的时候代码可以在不同的时候上调试,以后有时间一定要学习下这两种方式。

总结

rpmbuild打包一般步骤

  • 根据rpmbuild标准,创建打包的目录结构
  • 将源码和辅助文件放到指定目录
  • 编写spec文件,放到指定目录
  • 根据需要构建rpm,或者rpm和srpm等。

无网络时提前在有网络的机器上下载好依赖包就好啦

引用

How to create an RPM package/zh-hk

CentOS6下rpm打包实战

Centos 6 制作 rpm 包

Linux之rpm本地打包

SRPM包编译成RPM包之rpmbuild和mock

坚持原创技术分享,您的支持将鼓励我继续创作!