CentOS下 rpm 包制作

CentOS下 rpm 包制作

RPM(Red Hat Package Manager)是用于 Linux 分发版(distribution)的最常见的软件包管理器。因为它允许分发已编译的软件,所以用户只用一个命令就可以安装软件。RPM 是 Linux“标准基本库”版本 1.0.0 指定的安装工具。在 Linux 分发版前 10 名中,有 8 个是基于 RPM(请参阅“Comparison of Linux Distributions”)。即使某些通常不使用 RPM 的分发版,如 Debian,也有可用工具将 RPM 转换成它们自己的格式。在 Linux 上,对于除开发人员以外的任何人,RPM 也是用来打包软件的最佳选择。本文通过一个webhook,介绍rpm软件包的制作

使用centos7

准备环境

1
git clone https://github.com/XiaoMi/soar.git

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

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

1. 配置工作目录

安装构建工具

1
yum install rpmdevtools wget tree

使用命令生成工作目录

1
rpmdev-setuptree

rpmdev-setuptree 命令默认将再当前用户主目录下创建一个RPM构建根目录结构,
如果需要改变次默认位置,可以修改配置文件:~/.rpmmacros中变量 _topdir 对应
的值即可。

生成的目录如下

1
rpmbuild/
2
├── BUILD     # BUILD 打包过程中的工作目录
3
├── RPMS      # 存放生成的二进制包
4
├── SOURCES   # 放置打包资源,包括源码打包文件和补丁文件
5
├── SPECS     # SPECS 目录放置 SPEC 文档
6
└── SRPMS     # 目录存放生成的源码包

BUILDROOT 是制作过程中临时安装程序的地方

2. 制作过程概览

为了构建 RPM 软件包,您需要写一个名为 spec 文件的 RPM 输入文件,该文件告诉 RPM 如何构建和打包您的软件。编写 spec 文件您需要:

如果您首次创建 .spec 文件,vim 或 emacs 会自动生成模板:

1
Name:
2
Version:
3
Release:	1%{?dist}
4
Summary:
5
Group:
6
License:
7
URL:
8
Source0:
9
BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
10
11
BuildRequires:
12
Requires:
13
14
%description
15
16
%prep
17
%setup -q
18
19
%build
20
%configure
21
make %{?_smp_mflags}
22
23
%install
24
rm -rf %{buildroot}
25
make install DESTDIR=%{buildroot}
26
27
%clean
28
rm -rf %{buildroot}
29
30
%files
31
%defattr(-,root,root,-)
32
%doc
33
34
%changelog

您可以使用 $RPM_BUILD_ROOT 代替 %{buildroot},两者都可以使用。

spec文档的内容

1
Name: 软件包的名称,后面可使用%{name}的方式引用,具体命令需跟源包一致
2
Summary:                    软件包的内容概要
3
Version:                        软件的实际版本号,具体命令需跟源包一致
4
Release:                        发布序列号,具体命令需跟源包一致
5
Group:                          软件分组,建议使用标准分组

软件包所属类别,具体类别有:

Amusements/Games (娱乐/游戏)
Amusements/Graphics (娱乐/图形)
Applications/Archiving (应用/文档)
Applications/Communications (应用/通讯)
Applications/Databases (应用/数据库)
Applications/Editors (应用/编辑器)
Applications/Emulators (应用/仿真器)
Applications/Engineering (应用/工程)
Applications/File (应用/文件)
Applications/Internet (应用/因特网)
Applications/Multimedia (应用/多媒体)
Applications/Productivity (应用/产品)
Applications/Publishing (应用/印刷)
Applications/System (应用/系统)
Applications/Text (应用/文本)
Development/Debuggers (开发/调试器)
Development/Languages (开发/语言)
Development/Libraries (开发/函数库)
Development/System (开发/系统)
Development/Tools (开发/工具)
Documentation (文档)
System Environment/Base (系统环境/基础)
System Environment/Daemons (系统环境/守护)
System Environment/Kernel (系统环境/内核)
System Environment/Libraries (系统环境/函数库)
System Environment/Shells (系统环境/接口)
User Interface/Desktops (用户界面/桌面)
User Interface/X (用户界面/X窗口)
User Interface/X Hardware Support (用户界面/X硬件支持)

License: 软件授权方式,通常就是GPL

1
Source: 源代码包,可以带多个用Source1、Source2等源,后面也可以用%{source1}、%{source2}引用
2
BuildRoot: 这个是安装或编译时使用的“虚拟目录”,考虑到多用户的环境,一般定义为:
3
%{_tmppath}/%{name}-%{version}-%{release}-root 或 %{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n}
4
该参数非常重要,因为在生成[rpm](https://www.fooher.com/tag/rpm)的过程中,执行make install时就会把软件安装到上述的路径中,在打包的时候,同样依赖“虚拟目录”为“根目录”进行操作。
5
后面可使用$RPM_BUILD_ROOT 方式引用。

URL: 软件的主页

Vendor: 发行商或打包组织的信息,例如RedFlag Co,Ltd
Disstribution: 发行版标识
Patch: 补丁源码,可使用Patch1、Patch2等标识多个补丁,使用%patch0或%{patch0}引用
Prefix: %{_prefix} 这个主要是为了解决今后安装rpm包时,并不一定把软件安装到rpm中打包的目录的情况。这样,必须在这里定义该标识,并在编写%install脚本的时候引用,才能实现rpm安装时重新指定位置的功能
Prefix: %{_sysconfdir} 这个原因和上面的一样,但由于%{_prefix}指/usr,而对于其他的文件,例如/etc下的配置文件,则需要用%{_sysconfdir}标识
Build Arch: 指编译的目标处理器架构,noarch标识不指定,但通常都是以/usr/lib/rpm/marcros中的内容为默认值
Requires: 该rpm包所依赖的软件包名称,可以用>=或<=表示大于或小于某一特定版本,

spec脚本主体

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

%prep 预处理脚本

%setup -n %{name}-%{version} 把源码包解压并放好
注:可根据你的源码的名字格式,来确认解压后名字的格式,否则可能导致install的时候找不到对应的目录
通常是从/usr/src/redhat/SOURCES里的包解压到/usr/src/redhat/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 将所有打补丁时产生的输出文件删除。

预处理 %prep:

预处理通常用来执行一些解开源程序包的命令,为下一步的编译安装做准备。
%prep 和下面的 %build,%install 段一样,除了可以执行 RPM 所定义的
宏命令(以 % 开头)以外,还可以执行 SHELL 命令,功能类似 ./configure
作用:
用来准备要编译的软件。通常,这一段落将归档中的源代码解压,并应用补丁。
这些可以用标准的 Shell 命令完成,但是更多地使用预定义的宏.
检查标签语法是否正确,删除旧的软件源程序,对包含源程序的 tar 文件进行解码。
如果包含补丁(patch)文件,将补丁文件应用到解开的源码中。它一般包含 %setup
与 %patch 两个命令。%setup 用于将软件包打开,执行 %patch 可将补丁文件加入
解开的源程序中.

%prep
宏 %setup
该宏解开源代码,将当前目录改为源代码解压之后产生的目录。这个宏还有一些选项
可以使用,如,在解压后, %setup 宏假设产生的目录是 %{name}-%{version}
如果 tar 打包中的目录不是这样命名的,可以用 -n 选项来指定要切换到的目录。
如:%setup -n%{name}-April2003Rel
还有如下其他参数:
%setup -q — 将 tar 命令的繁复输出关闭
%setup -nnewdir — 将压缩的软件源程序在 newdir 目录下解开
%setup -c — 在解开源程序之前先创建目录
%setup -bnum — 在包含多个源程序时,将第 num 个源程序解压缩
%setup -T — 不使用缺省的解压缩操作

%files 基础

%defattr 用于设置默认文件权限,通常可以在 %files 的开头看到它。注意,如果不需要修改权限,则不需要使用它。其格式为:

1
%defattr(<文件权限>, <用户>, <用户组>, <目录权限>)

第 4 个参数通常会省略。常规用法为 %defattr(-,root,root,-),其中 “-“ 表示默认权限。

您应该列出该软件包拥有的所有文件和目录。尽量使用宏代替目录名,查看宏列表 Packaging:RPMMacros(例如:使用 %{_bindir}/mycommand 代替 /usr/bin/mycommand)。如果路径以 “/“ 开头(或从宏扩展),则从 %{buildroot} 目录取用。否则,假设文件在当前目录中(例如:在 %{_builddir} 中,包含需要的文档)。如果您的包仅安装一个文件,如 /usr/sbin/mycommand,则 %files 部分如下所示:

1
%files
2
%{_sbindir}/mycommand

若要使软件包不受上游改动的影响,可使用通配符匹配所有文件:

1
%{_bindir}/*

包含一个目录:

1
%{_datadir}/%{name}/

注意,%{_bindir}/* 不会声明此软件包拥有 /usr/bin 目录,而只包含其中的文件。如果您列出一个目录,则该软件包拥有这个目录,及该目录内的所有文件和子目录。因此,不要列出 %{_bindir},并且要小心的处理那些可能和其他软件包共享的目录。

如果存在以下情况,可能引发错误:

  • 通配符未匹配到任何文件或目录
  • 文件或目录被多次列出
  • 未列出 %{buildroot} 下的某个文件或目录
  • 您也可以使用 %exclude 来排除文件。这对于使用通配符来列出全部文件时会很有用,注意如果未匹配到任何文件也会造成失败。

您可能需要在 %files 部分添加一个或多个前缀;请用空格分隔。详情请查看 Max RPM section on %files directives

通常,”%doc“ 用于列出 %{_builddir} 内,但未复制到 %{buildroot} 中的文档。通常包括 READMEINSTALL。它们会保存至 /usr/share/doc 下适当的目录中,不需要声明 /usr/share/doc 的所有权。

注意: 如果指定 %doc 条目,rpmbuild < 4.9.1 在安装前会将 %doc 目录删除。这表明已保存至其中的文档,例如,在 %install 中安装的文档会被删除,因此最终不会出现在软件包中。如果您想要在 %install 中安装一些文档,请将它们临时安装到 build 目录(不是 build root 目录)中,例如 _docs_staging,接着在 %files 中列出,如 %doc _docs_staging/* 这样。

配置文件保存在 /etc 中,一般会这样指定(确保用户的修改不会在更新时被覆盖):

1
%config(noreplace) %{_sysconfdir}/foo.conf

如果更新的配置文件无法与之前的配置兼容,则应这样指定:

1
%config %{_sysconfdir}/foo.conf

%attr(mode, user, group)“ 用于对文件进行更精细的权限控制,”-“ 表示使用默认值:

1
%attr(0644, root, root) FOO.BAR

%caps(capabilities)“ 用于为文件分配 POSIX capabilities。例如:

1
%caps(cap_net_admin=pe) FOO.BAR

如果包含特定语言编写的文件,请使用 %lang 来标注:

1
%lang(de) %{_datadir}/locale/de/LC_MESSAGES/tcsh*

使用区域语言(Locale)文件的程序应遵循 处理 i18n 文件的建议方法

  • %install 步骤中找出文件名: %find_lang ${name}
  • 添加必要的编译依赖: BuildRequires: gettext
  • 使用找到的文件名: %files -f ${name}.lang

以下前缀在 Fedora 中无效%license%readme

常用的宏

1
RPM_BUILD_DIR:          /usr/src/redhat/BUILD
2
RPM_BUILD_ROOT:         /usr/src/redhat/BUILDROOT
3
%{_sysconfdir}:         /etc
4
%{_sbindir}:           /usr/sbin
5
%{_bindir}:             /usr/bin
6
%{_datadir}:            /usr/share
7
%{_mandir}:             /usr/share/man
8
%{_libdir}:             /usr/lib64
9
%{_prefix}:             /usr
10
%{_localstatedir}:      /usr/var
11
%{_unitdir}             /usr/lib/systemd/system/
%{_bindir} /usr/bin 二进制目录:保存可执行文件
%{_builddir} ~/rpmbuild/BUILD 构建目录:软件在 build 的子目录被编译。参考 %buildsubdir
%{buildroot} ~/rpmbuild/BUILDROOT Build root:%install 阶段中,将 %{_builddir} 子目录下的文件复制到 %{buildroot} 的子目录(之前,%{buildroot}使用的位置为 “/var/tmp/“)
%{buildsubdir} %{_builddir}/%{name} 构建子目录:%build 阶段中,文件会在 %{_builddir} 的子目录中编译。此宏在 %autosetup 之后设置
%{_datadir} /usr/share 共享数据目录
%{_defaultdocdir} /usr/share/doc 默认文档目录
%{dist} .fc*NUMBER* 发行版名称+版本号(例如 “.fc30“)
%{fedora} *NUMBER* Fedora 发行版本号(例如 “30“)
%{_includedir} /usr/include 程序头文件目录
%{_infodir} /usr/share/info info 手册目录
%{_initrddir} /etc/rc.d/init.d init 脚本目录
%{_libdir} /usr/lib 共享库目录
%{_libexecdir} /usr/libexec 仅由系统调用执行该目录中的命令
%{_localstatedir} /var 保存缓存/日志/lock等信息的目录
%{_mandir} /usr/share/man man 手册目录
%{name} 软件包名称,通过 Name: tag 设置
%{_sbindir} /usr/sbin 保存管理员可执行命令
%{_sharedstatedir} /var/lib 保存程序运行所处理的文件
%{_sysconfdir} /etc 配置文件目录
%{version} 软件包版本,通过 Version: tag 设置

您可以查看 /etc/rpm/*/usr/lib/rpm,以及 /usr/lib/rpm/macros 以进一步了解宏。或使用 rpm --showrc 显示当前 RPM 所使用的宏变量和值(根据 rpmrc 和宏)

1
%define debug_package %{nil}
2
Name: webhooks
3
Version: 0.1.1
4
Release:	1%{?dist}
5
Summary: a git sync tools
6
7
Group:  Development/Tools
8
License: GPL
9
URL: http://www.github.com/becivells/go-webhook
10
Source0: %{name}-%{version}.tar.gz
11
Source1: webhooks.service
12
13
BuildRoot: %{_tmppath}/%{name}-%{main_version}-%{main_release}-root
14
%description
15
a git tool for repo to webroot
16
17
%prep
18
%setup -q
19
20
%build
21
go build -o webhooks
22
23
%install
24
%{__rm} -rf $RPM_BUILD_ROOT
25
%{__mkdir} -p $RPM_BUILD_ROOT/usr/lib/systemd/system/
26
%{__mkdir} -p $RPM_BUILD_ROOT/opt/webhooks
27
%{__install} -m755  webhooks $RPM_BUILD_ROOT/opt/webhooks/webhooks
28
%{__install}  webhooks.yaml $RPM_BUILD_ROOT/opt/webhooks/webhooks.yaml
29
%{__install} -m644  %SOURCE1  $RPM_BUILD_ROOT/%{_unitdir}/webhooks.service
30
31
%files
32
%defattr(-,root,root,-)
33
/opt/webhooks/
34
/usr/lib/systemd/system/
35
%clean
36
%{__rm} -rf $RPM_BUILD_ROOT

https://github.com/Becivells/linux-package

https://www.cnblogs.com/jimodetiantang/p/9573098.html

https://www.fooher.com/20180112_155.html

https://fedoraproject.org/wiki/How_to_create_an_RPM_package/zh-cn