大多数 rpm 包的制作都是用源码包来编译构建,而我的需求是直接将可运行的二进制文件制作成 rpm 包,而且是在 Ubuntu 系统上。网上的大部分资料都是源码来制作 rpm 包,且比较零乱、不完整。rpm 制作的重要一步就是编写 spec 文件,在该文件中定义了如何编译源码,然后又如何打包的过程。通过大量的资料查阅和分析,最后发现在 spec 文件中把 源码编译的部分删掉便可以直接将二进制文件制作成 rpm 包。
安装 rpm 工具

制作 rpm 包需要用到 rpmbuild 工具。在 ubuntu 上,该工具包含在 rpm 包中,可以直接从源里安装:
sudo apt-get install rpm

配置工作路径

在制作 rpm 包之前,首先要配置工作路径,也就是制作 rpm 包所在的目录。制作 rpm 包需要有一个特定的目录结构。当前的工作路径保存在宏 % _topdir 中,可以通过 rpmbuild 命令查看:

rpmbuild --showrc | grep topdir

默认情况下工作路径为当前用户目录下的 rpmbuild 目录。如果你不想在用户目录下的rpmbuild目录制作rpm包,可以在当前用户目录下的 .rpmmacros 文件

(如果没有,则创建 touch~/.rpmmacros,加入 %_topdir /home/lili/workdir/rpmbuild)

中修改宏 %_topdir 的配置,例如:

%_topdir /home/lili/workdir(你的工作路径)


建立构建目录结构

在类 redhat 系统中,可以用 rpmdev-setuptree 命令直接在常见所需的目录结构,而在 Ubuntu 系统貌似没有该工具,那么手动创建即可:

mkdir -pv /home/lili/workdir/rpmbuild/{BUILD,buildrOOT,RPMS,SOURCES,Specs,SRPMS}

目录说明:

BUILD 编译之前,如解压包后存放的路径
buildrOOT 编译后存放的路径
RPMS 打包完成后rpm包存放的路径
SOURCES 源包所放置的路径
Specs spec文档放置的路径
SPRMS 源码rpm包放置的路径
通过源码编译制作软件包时, 一般都把源码打包成 tar.gz 格式然后存放于 SOURCES 路径下,而在 Specs 路径下编写 spec 文档,编译生成的二进制文件会临时的存放在 buildrOOT 目录下等待打包,打包完成后会被删除,通过命令打包后,默认会把打包后的 rpm 包放在 RPMS 下,而源码包会被放置在SRPMS下。

编写 spec 文件

在我看来, spec 文件核心的部分就只有两个部分:一个是软件包的基本信息描述部分,其中 Name、Version、 Release 三个字段是必须的,最终生成的软件包的名字会依赖于此;另一个是 %files 段,它定义需要打包的文件。剩下的大致也可以分为两个部分:一个是定义源码的编译过程,这里不做详述;另一个是定义安装和卸载前后要做的工作,主要在四个段中定义:

%pre
在安装包之前运行
%post
在安装包之后运行
%preun
在卸载包之前运行
%postun

在卸载包之后运行


对于 %files 阶段有两个比较重要的特性:

%{buildroot}里的所有文件都要明确被指定是否要被打包到rpm里。例如,%{buildroot}目录下有4个目录a、b、c和d,在%files里仅指定a和b要打包到rpm里,如果不把c和d用exclude声明是要报错的;

如果声明了%{buildroot}里不存在的文件或者目录也会报错。

下面是一个 spec 文件模板:

# 这个区域定义的Name、Version这些字段对应的值可以在后面
# 通过%{name},%{version}这样的方式来引用,类似于C语言中的宏

# Name制定了软件的名称
Name: Nginx
# 软件版本
Version: 1.5.2
# 释出号,也就是第几次制作rpm
Release: 1%{?dist}
# 软件的介绍,必须设置,最好不要超过50个字符
Summary: Nginx from WangYing

# 软件的分组,可以通过/usr/share/doc/rpm-4.8.0/GROUPS文件中选择,也可以
# 在相应的分类下,自己创建一个新的类型,例如这里的Server
Group: Application/Server
# 许可证类型
License: GPL
# 软件的源站
URL: http://Nginx.org
# 制作rpm包的人员信息
Packager: WangYing
# 源码包的名称,在%_topdir/SOURCE下,如果有多个源码包的话,可以通过
# Source1、Source2这样的字段来指定其他的源码包
Source0: %{name}-%{version}.tar.gz
# buildroot指定了make install的测试安装目录,通过这个目录我们可以观察
# 生成了哪些文件,方便些files区域。如果在files区域中写的一些文件报
# 不存在的错误,可以查看%_topdir/buildrOOT目录来检查有哪些文件。
buildroot: %_topdir/buildrOOT
# 指定安装的路径
Prefix: /usr/local/Nginx-1.5.2

# 制作过程需要的工具或软件包
buildrequires: gcc,make
# 安装时依赖的软件包
Requires: pcre,pcre-devel,openssl

# 软件的描述,这个可以尽情地写
%description
Nginx is a http server

# %prep指定了在编译软件包之前的准备工作,这里的
# setup宏的作用是静默模式解压并切换到源码目录中,
# 当然你也可以使用tar命令来解压
%prep
%setup -q

# 编译阶段,和直接编译源代码类似,具体的操作或指定的一些参数由configure文件决定。
%build
CFLAGS="-pipe -O2 -g -W -Wall -Wpointer-arith -Wno-unused-parameter -Werror" ./configure --prefix=%{prefix}
# make后面的意思是:如果是多处理器,则并行编译
make %{?_smp_mflags}

# 安装阶段
%install
# 先删除原来的测试安装的,只有在制作失败了%{buildroot}目录才会有内容,
# 如果成功的话,目录下会被清除。
# %{buildroot}指向的目录不是buildroot(%_topdir/buildrOOT)指定的目录,
# 而是该目录下名称与生成的rpm包名称相同的子目录。例如我的是
# /usr/src/redhat/buildrOOT/Nginx-1.5.2-1.el6.x86_64
rm -rf %{buildroot}
# 指定安装目录,注意不是真实的安装目录,是在制作rpm包的时候指定的
# 安装目录,如果不指定的话,默认就会安装到configure命令中指定的prefix路径,
# 所以这里一定要指定DESTDIR
make install DESTDIR=%{buildroot}

# 安装前执行的脚本,语法和shell脚本的语法相同
%pre

# 安装后执行的脚本
%post

# 卸载前执行的脚本,我这里的做的事情是在卸载前将Nginx服务器停掉
%preun
MSG=`ps aux | grep Nginx | grep -v "grep"`
if [ -z "$MSG" ];then
killall Nginx 1>/dev/null 2>/dev/null
fi

# 卸载完成后执行的脚本
%postun
rm -rf %{prefix}

# 清理阶段,在制作完成后删除安装的内容
%clean
rm -rf %{buildroot}

#指定要包含的文件
%files
#设置默认权限,如果没有指定,则继承默认的权限
%defattr (-,root,0755)
%{prefix}
spec 文档中常用的几个宏(变量):

RPM_BUILD_DIR: /usr/src/redhat/BUILD
RPM_BUILD_ROOT: /usr/src/redhat/buildrOOT
%{_sysconfdir}: /etc
%{_sbindir}: /usr/sbin
%{_bindir}: /usr/bin
%{_datadir}: /usr/share
%{_mandir}: /usr/share/man
%{_libdir}: /usr/lib64
%{_prefix}: /usr
%{_localstatedir}: /usr/var
开始打包

制作 rpm 包需要用 rpmbuild 命令,其基本格式为:

rpmbuild [options] [spec文档|tarball包|源码包]

从spec文档建立有以下选项:

-bp #只执行spec的%pre 段(解开源码包并打补丁,即只做准备)
-bc #执行spec的%pre和%build 段(准备并编译)
-bi #执行spec中%pre,%build与%install(准备,编译并安装)
-bl #检查spec中的%file段(查看文件是否齐全)
-ba #建立源码与二进制包(常用)
-bb #只建立二进制包(常用)
-bs #只建立源码包
从 tarball 包建立

-tp #对应-bp
-tc #对应-bc
-ti #对应-bi
-ta #对应-ba
-tb #对应-bb
-ts #对应-bs
3. 从源码包建立
--rebuild #建立二进制包,通-bb
--recompile #同-bi
其他的一些选项

--buildroot=DIRECTORY #确定以root目录建立包
--clean #完成打包后清除BUILD下的文件目录
--nobuild #不进行%build的阶段
--nodeps #不检查建立包时的关联文件
--nodirtokens
--rmsource #完成打包后清除SOURCES
--rmspec #完成打包后清除SPEC
--short-cricuit
--target=cpu-vendOR-OS #确定包的最终使用平台
例如我的构建方式为:

在 Ubuntu 下制作 rpm 包时,会默认将 buildrOOT 目录下的 {name}-{version}-{release}-{arch} 的目录作为 {buildroot} 目录,所以要打包的文件必须放在该目录下才能完成打包,否则 rpmbuild 找不到文件。也就是说,我必须将要打包的 /usr/bin/ 目录下的所有文件 放到 /home/lili/workdir/rpmbuild/buildrOOT/codeblocks-13.12-1.arm 目录下才能完成打包

1.mkdir -pv /home/lili/workdir/rpmbuild/buildrOOT/codeblocks-13.12-1.arm/usr/bin/

2.touch /home/lili/workdir/rpmbuild/buildrOOT/codeblocks-13.12-1.arm/usr/bin/document


得到的目录结构:

└── rpmbuild
├── BUILD
├── buildrOOT
│ └── codeblocks-13.12-1.arm
│ └── usr
│ └── bin
│ └── document
├── RPMS
│ └── armv7l
│ └── codeblocks-13.12-1.armv7l.rpm
├── SOURCES
├── Specs
│ └── codeblocks.spec
└── SRPMS

3.rpmbuild -bb --target=armv7l Specs/codeblocks.spec


构建过程输出如下信息:
Building target platforms: armv7l
Building for target armv7l
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.dqIHUu
+ umask 022
+ cd /home/lili/workdir/rpmbuild/BUILD
+ exit 0
Processing files: codeblocks-13.12-1.armv7l
Provides: codeblocks = 13.12-1 codeblocks(armv7l-32) = 13.12-1
Requires(interp): /bin/sh /bin/sh /bin/sh /bin/sh
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires(pre): /bin/sh
Requires(post): /bin/sh
Requires(preun): /bin/sh
Requires(postun): /bin/sh
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/lili/workdir/rpmbuild/buildrOOT/codeblocks-13.12-1.arm
Wrote: /home/lili/workdir/rpmbuild/RPMS/armv7l/codeblocks-13.12-1.armv7l.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.YDo80Y
+ umask 022
+ cd /home/lili/workdir/rpmbuild/BUILD
+ /bin/rm -rf /home/lili/workdir/rpmbuild/buildrOOT/codeblocks-13.12-1.arm
+ exit 0


本文要讲的主要内容在 Ubuntu 下直接将编译好的二进制文件制作成 rpm 包,以上的内容只是为了更为详细的了解 rpm 包制作的过程。或许你已经发现,要直接将编译好的二进制文件打包,只需要在 spec 文件中将源码编译的部分略去,而把 %files 段详细写明即可。例如我的 spec 文件:

Name: codeblocks
Version: 13.12
Release: 1
Summary: OpenSource Cross Platform Free C++ IDE
Group: Development/Tools/IDE
License: GPLv3+
URL: http://www.codeblocks.org/
Packager:Li Li

%define _bindir /usr/bin

%description
Code::Blocks is the open-source,cross-platform Integrated Development Environment (IDE).

It is based on a self-developed plugin framework allowing unlimited extensibility. Most of its functionality is already provided by plugins.

 Plugins included in the base package are:
  * Compiler frontend to many free compilers
  * Debugger frontend for GDB (and CDB for windows platforms)
  * Source formatter (based on AStyle)
  * Wizard to create new C++ classes
  * Code-completion / symbols-browser (work in progress)
  * Default MIME handler
  * Wizard to create new Code::Blocks plugins
  * To-do list
  * Extensible wizard based on scripts
  * Autosave (saves your work in the unfortunate case of a crash)

%prep

%pre
echo -e '\033[0;31;5m'
echo "------------- Installation Statement -------------"
echo "Cdoeblocks depends on wxwidget 2.8.12 and above."
echo "And depends on boost,gamin,hunspell."
echo "Make sure the system has been installed them."
echo "Otherwise the program will not run properly"
echo -e '\033[0m'


%post
echo "--------- after Statement -------------"
echo "----------do post work--------"
/usr/bin/chmod a+x /usr/bin/document
%preun

%postun

%files
%defattr(-,-)
%{_bindir}


构建成功。


安装到arm板子上:

root@localhost:~# rpm -ivh /root/codeblocks-13.12-1.armv7l.rpm --force --nodeps
Preparing... ################################# [100%]
No manifest in this package. Creating default one

------------- Installation Statement -------------
Cdoeblocks depends on wxwidget 2.8.12 and above.
And depends on boost,hunspell.
Make sure the system has been installed them.
Otherwise the program will not run properly

Updating / installing...
1:codeblocks-13.12-1 ################################# [100%]
--------- after Statement -------------
----------do post work--------

查询arm板子上的rpm包

root@localhost:~# rpm -qa |grep codeblocks
codeblocks-13.12-1.armv7l


参考资料 http://blog.konghy.cn/2015/11/13/rpmbuild/ https://fedoraproject.org/wiki/How_to_create_an_RPM_package/zh-cn http://blog.csdn.net/justlinux2010/article/details/9905425 http://blog.chinaunix.net/uid-23069658-id-3944462.html http://www.jinbuguo.com/redhat/rpmbuild.html

在 Ubuntu 下直接将二进制文件制作成 rpm 包的更多相关文章

  1. HTML实现代码雨源码及效果示例

    这篇文章主要介绍了HTML实现代码雨源码及效果示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  2. ios – Xcode警告:“没有处理文件的规则”和“找不到目录”

    重命名我的项目文件夹后,我收到以下错误消息:什么可能出错?解决方法关于第一个警告,您可以在项目设置中的“构建阶段”中检查XCode,即头文件不会出现在“编译源”列表中.

  3. 你如何将xcode项目转换为cocoapod?

    我有一段代码,我发现我在多个不同的项目中重复使用,所以我想把它变成一个cocoapod并使用私人cocoapod仓库.我的问题是如何将xcode项目设置为cocoapod?它应该是一个静态库还是一个带有appdelegate的空“项目”?

  4. ios – 如何将文件添加到主包的/ Library / Sounds目录中?

    根据Apple’sdocumentation,/Library/Sounds中的声音文件将在尝试播放声音时由系统搜索.如何将声音文件添加到此文件夹?适用于iOS的正确文档应为here总之,您只需将声音文件作为应用程序包的非本地化资源添加到项目中.

  5. ios – 资产目录与文件夹参考:何时使用其中一个?

    我可以将文件放入Assets.xcassets,或者我可以将文件放入文件夹引用.我何时会选择一个而不是另一个?

  6. ios – 从icloud备份中限制sqlite-wal和sqlite-shm

    我是第一次使用coredata,我必须从文档目录中的iCloud备份限制sqlitedb文件,我使用下面的代码完成了它//阻止iCloud备份文档目录文件夹现在我不明白的是,我们还需要从icloud备份中限制sqlite-wal和sqlite-shm文件,如果是,那么如何从icloud备份限制sqlite-wal和sqlite-shm文件我想要一个解决方案,而无需从文档目录文件夹中更改sqlitedb位置…

  7. iOS:如何从文档目录中删除具有特定扩展名的所有现有文件?

    当我更新我的iOS应用程序时,我想删除Documents目录中的任何现有sqlite数据库.现在,在应用程序更新时,我将数据库从软件包复制到文档目录,并通过附加软件包版本来命名它.因此,在更新时,我还想删除可能存在的任何旧版本.我只是希望能够删除所有sqlite文件,而无需循环浏览并查找以前版本的文件.是否有任何方法可以对removeFileAtPath:方法进行通配符?解决方法那么,你想要删除所有*.sqlite文件?

  8. .dylib在Debug中链接,在XCode中找不到适用于iPhone的版本

    所以我已经将libxml2.2.dylib库包含在我的iPhoneXCode项目中,以创建一些Xml和XPath解析实用程序.当我编译并运行在模拟器和设备的调试模式时,我没有问题,但是,当我切换到发布模式我得到…

  9. ios – 从文件目录加载UIImage

    我正在尝试从文件目录加载一个UIImage,并将其设置为UIImageView,如下所示:但是,每当我尝试以上,图像从不加载.该图像在Documents/MyAppCustomDirectory/school.png中.以上是否正确从该目录加载?我也尝试了其他几个:UIImageimageWithContentsOfFile,以及基于SO响应的其他方法.解决方法要获取您应该使用的文档目录:我不太清

  10. Xcode 6 / iOS 8模拟器数据和软件包文件夹脚本

    随着xcode6的最新更改,它看起来像.app文件和文档文件夹不再驻留在iPhone模拟器目录中的同一个文件夹中.以前,我们可以访问目录和.app文件但在Xcode6中,模拟器目录是完全不同的:和其中CryptNumber1,2和3都不同.有没有办法找到包含.app文件的文件夹后,我可以得到相应的文件夹?我有这个麻烦.为什么…?

随机推荐

  1. crontab发送一个月份的电子邮件

    ubuntu14.04邮件服务器:Postfixroot收到来自crontab的十几封电子邮件.这些邮件包含PHP警告.>我已经解决了这些警告的原因.>我已修复每个cronjobs不发送电子邮件(输出发送到>/dev/null2>&1)>我删除了之前的所有电子邮件/var/mail/root/var/spool/mail/root但我仍然每小时收到十几封电子邮件.这些电子邮件来自cronjobs,

  2. 模拟两个ubuntu服务器计算机之间的慢速连接

    我想模拟以下场景:假设我有4台ubuntu服务器机器A,B,C和D.我想在机器A和机器C之间减少20%的网络带宽,在A和B之间减少10%.使用网络模拟/限制工具来做到这一点?

  3. ubuntu-12.04 – 如何在ubuntu 12.04中卸载从源安装的redis?

    我从源代码在Ubuntu12.04上安装了redis-server.但在某些时候它无法完全安装,最后一次makeinstallcmd失败.然后我刚刚通过apt包安装.现在我很困惑哪个安装正在运行哪个conf文件?实际上我想卸载/删除通过源安装的所有内容,只是想安装一个包.转到源代码树并尝试以下命令:如果这不起作用,您可以列出软件自行安装所需的步骤:

  4. ubuntu – “apt-get source”无法找到包但“apt-get install”和“apt-get cache”可以找到它

    我正在尝试下载软件包的源代码,但是当我运行时它无法找到.但是当我运行apt-cache搜索squid3时,它会找到它.它也适用于apt-getinstallsquid3.我使用的是Ubuntu11.04服务器,这是我的/etc/apt/sources.list我已经多次更新了.我尝试了很多不同的debs,并没有发现任何其他地方的错误.这里的问题是你的二进制包(deb)与你的源包(deb-src)不

  5. ubuntu – 有没有办法检测nginx何时完成正常关闭?

    &&touchrestarted),因为即使Nginx没有完成其关闭,touch命令也会立即执行.有没有好办法呢?这样的事情怎么样?因此,pgrep将查找任何Nginx进程,而while循环将让它坐在那里直到它们全部消失.你可以改变一些有用的东西,比如睡1;/etc/init.d/Nginx停止,以便它会休眠一秒钟,然后尝试使用init.d脚本停止Nginx.你也可以在某处放置一个计数器,这样你就可以在需要太长时间时发出轰击信号.

  6. ubuntu – 如何将所有外发电子邮件从postfix重定向到单个地址进行测试

    我正在为基于Web的应用程序设置测试服务器,该应用程序发送一些电子邮件通知.有时候测试是使用真实的客户数据进行的,因此我需要保证服务器在我们测试时无法向真实客户发送电子邮件.我想要的是配置postfix,以便它接收任何外发电子邮件并将其重定向到一个电子邮件地址,而不是传递到真正的目的地.我正在运行ubuntu服务器9.10.先感谢您设置本地用户以接收所有被困邮件:你需要在main.cf中添加:然后

  7. ubuntu – vagrant无法连接到虚拟框

    当我使用基本的Vagrantfile,只配置了两条线:我看到我的虚拟框打开,但是我的流氓日志多次显示此行直到超时:然后,超时后的一段时间,虚拟框框终于要求我登录,但是太久了!所以我用流氓/流氓记录.然后在我的物理机器上,如果我“流氓ssh”.没有事情发生,直到:怎么了?

  8. ubuntu – Nginx – 转发HTTP AUTH – 用户?

    我和Nginx和Jenkins有些麻烦.我尝试使用Nginx作为Jenkins实例的反向代理,使用HTTP基本身份验证.它到目前为止工作,但我不知道如何传递带有AUTH用户名的标头?}尝试将此指令添加到您的位置块

  9. Debian / Ubuntu – 删除后如何恢复/ var / cache / apt结构?

    我在ubuntu服务器上的空间不足,所以我做了这个命令以节省空间但是现在在尝试使用apt时,我会收到以下错误:等等显然我删除了一些目录结构.有没有办法做apt-getrebuild-var-tree或类似的?

  10. 检查ubuntu上安装的rubygems版本?

    如何查看我的ubuntu盒子上安装的rubygems版本?只是一个想法,列出已安装的软件包和grep为ruby或宝石或其他:)dpkg–get-selections

返回
顶部