使用rpmbuild将源代码制成rpm包

1 说明

因centos停止支持,需要将一些应用软件迁移到OpenEuler上。原本在centos上只需要直接安装官网提供的预编译rpm包即可,现在没有了现成的安装包,只能从源代码自行编译。如果只是少数机器,逐台编译尚可忍耐,对于大量机器需要安装的情况,显然还是制作成rpm更为合适。

本文内容整理自官网文档:https://rpm-packaging-guide.github.io/,将其中的一个实例进行了解释,供学习之用。

2 准备源代码

2.1 C语言程序

创建目录cello-1.0,在其中创建一个输出Hello World的C语言程序文件cello.c:

复制代码
mkdir cello-1.0
cd cello-1.0
touch cello.c

cello.c内容如下:

复制代码
#include <stdio.h>

int main(void) {
    printf("Hello World\n");
    return 0;
}

用gcc将该程序编译链接,即可直接运行:

复制代码
yun install -y gcc
gcc -g -o cello cello.c

此时目录下会出现一个cello的可执行文件,直接使用./cello 即可输出Hello World。

如果将该可执行文件放在PATH路径下,那么在任何目录都可以直接使用cello命令执行。

2.2 补丁文件

在cello-1.0目录下创建一个普通文件cello.conf,假设为配置文件,安装完成后准备放在/etc/cello/目录下,内容为"before" 。

复制代码
echo "before"  > cello.conf

这个文件内容计划在安装完成后被修改,因此需要用到补丁。创建内容为"after"的cello2.conf文件,并用diff命令生成补丁。生成后将cello2.conf文件删除,将补丁文件cello-patch.patch复制到上层目录下,后面另有用处,只保留原文件cello.conf。

复制代码
echo "after"  > cello2.conf
diff -Naur cello.conf cello2.conf > cello-patch.patch
rm -f cello2.conf
mv cello-patch.patch ..

可以用patch < cello-patch.patch进行补丁功能的测试。

2.3 说明文件

在cello-1.0目录下再创建一个README.md,假设为说明文件,安装完成后准备放在/usr/share/doc/cello-1.0/目录下,文件内容随意。

2.4 Makefile文件

除了用gcc直接编译、链接,使用make工具可以更方便、更规范的完成这个流程。首先确保已经安装了make工具:

复制代码
yum install -y make

编写Makefile内容如下:

复制代码
cello:
        gcc -g -o cello cello.c
install:
        mkdir -p $(DESTDIR)/usr/bin
        install -m 0755 cello $(DESTDIR)/usr/bin/cello
clean:
        rm -f cello
        rm -f $(DESTDIR)/usr/bin/cello
  • 运行make或者make cello命令,则会在当前目录下生成可执行文件cello。
  • 运行make install命令,则会将cello文件复制到(DESTDIR)/usr/bin/cello目录下,并赋予755的权限。这里的(DESTDIR)是一个宏,可以人工指定(后面spec文件的%make_install部分会涉及),如果不指定则为根目录/。
  • 运行make clean,则会将当前目录下的cello删除,同时将$(DESTDIR)/usr/bin/cello目录下的cello删除。
  • 运行make distclean(本例中未涉及configure操作),除了同make clean外,还会将Makefile、config.log等文件一起删除,用于重新configure

2.5 总结

至此,源代码文件就准备好了。此时整个cello-1.0目录下,一共有4个文件:

复制代码
└── cello-1.0
    ├── cello.c
    ├── cello.conf
    ├── Makefile
    └── README.md

进入上层目录,将cello-1.0目录打包成tar.gz文件,以便进行下一步工作

复制代码
cd ..
tar -zcvf cello-1.0.tar.gz cello-1.0/

3 制作rpm包

3.1 安装工具

复制代码
yum install -y rpm-build
yum install -y rpmdevtools

3.2 构建工作空间

使用rpmdev-setuptree命令构建打包工作空间,该工作空间会创建在当前用户的家目录下,例如/root/rpmbuild,该目录结构如下:

复制代码
└── rpmbuild
    ├── BUILD
    ├── RPMS
    ├── SOURCES
    ├── SPECS
    └── SRPMS

各目录解释如下:

目录 内容
BUILD 主要是解压后的源代码
RPMS 如果制作的是RPM包,则存放在此
SOURCES 存放源代码包、补丁等
SPECS 制作时使用的spec文件
SRPMS 如果制作的是SRPM包,则存放在此
BUILDROOT 制作rpm包时才会生成,源代码会安装在此目录而非系统目录,以及放置文档、license等

3.3 编辑spec文件

将准备好的源代码文件cello-1.0.tar.gz和补丁文件cello-patch.patch放入SOURCES目录。

进入SPECS目录,创建新spec文件

复制代码
cd SPECES
rpmdev-newspec

会生成一个新的spec文件newpackage.spec,本例中修改为cello.spec,内容如下:

复制代码
Name:           cello
Version:        1.0 
Release:        1%{?dist}
Summary:        test
License:        GPLv3+ 
Source0:        %{name}-%{version}.tar.gz
Patch0:         cello-patch.patch
BuildRequires:        gcc, make

%description
test-1

%prep
%setup -q

%patch0

%build
make %{?_smp_mflags}

%install
%make_install
mkdir -p $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}
install -m 0644 %{name}.conf $RPM_BUILD_ROOT/%{_sysconfdir}/%{name}/%{name}.conf

%files
%doc README.md
%attr(0755, vmuser, vmuser) %{_bindir}/%{name}
%attr(0644, vmuser, vmuser) %{_sysconfdir}/%{name}/%{name}.conf

%postun
if [ "$1" = "0" ]; then
    rmdir %{_sysconfdir}/%{name}
fi

spec文件主要构成有:

  1. Preamble Items
    包含了包的元数据,这些项可以作为宏在spec文件中使用,以提高文件的可移植性。
关键字 说明
Name 包的名称
Version 包的版本
Release release版本
Summary 简要说明
License 遵循的License
Source0 使用的源代码包,如果有多个可以有Source1、 Source2......,由于使用了宏,替换后这里的源代码包即为cello-1.0.tar.gz
Patch0 使用的补丁,可以有多个:Patch1、Patch2......
BuildRequires build时需要的包
Requires 运行时需要的包,本例中无
  1. Body Items
    用于编译过程中的阶段控制。为提高文件的可移植性,文件中使用了一些宏,可参考下一小节。
关键字 说明
%description 说明描述
%prep 准备阶段,%setup -q意为将源代码压缩包(即cello-1.0.tar.gz)解压,并限制输出
%build 构建阶段,make %{?_smp_mflags}意为调用多处理器并行构建
%install 安装阶段,%make_install意为调用make install命令,此时(DESTDIR)不为系统跟目录,而是该工作空间的RPM_BUILD_ROOT目录,实际为/BUILDROOT/cello-1.0-1.el7.x86_64/。再应用install命令将conf文件复制到%{_sysconfdir}/%{name}/%下,即/etc/cello/下
%files 文件声明,将$RPM_BUILD_ROOT下的文件复制到系统的根目录/下。本例中是将README复制到/usr/shar/doc/cello-1.0/下(默认);cello可执行文件复制为%{_bindir}/%{name},实际为/usr/bin/cello,权限755;cello.conf复制到%{_sysconfdir}/%{name}/%{name}.conf,实际为/etc/cello/cello.conf,权限644
%postun 卸载后操作,本例中会保留一个空目录%{_sysconfdir}/%{name},即/etc/cello,因此需要删除

  1. SPEC文件中使用的宏,除了如%{name}、%{version}等关键字外,还有rpm定义的宏,例如%{_sysconfdir}和%{_bindir},这些宏具体说明可以在 /usr/lib/rpm/macros 文件中查看。
    常用的rpm宏例如:
说明
% bin目录,默认为/usr/bin
% sbin目录,默认为/usr/sbin
% 配置目录,默认为/etc
% 数据目录,默认为/usr/share

此类宏可以用rpm --eval %{_bindir}命令输出具体值。

3.4 创建rpm包

至此,rpmbuild目录结构如下:

复制代码
└── rpmbuild
    ├── BUILD
    ├── BUILDROOT
    ├── RPMS
    ├── SOURCES
    │   └── cello-1.0.tar.gz
    │   └── cello-patch.patch
    ├── SPECS
    │   └── cello.spec
    └── SRPMS

应用命令rpmbuild -bb SPECS/cello.spec即可进行rpm包的创建,其中bb为选项之一:

选项 说明
-bp build prep,只执行spec的%pre段
-bc build compile,只执行spec的%pre和%build段
-bi build install,只执行spec的%pre、%build和%install段
-bl 检查spec中的%file段
-ba 同时做成rpm和src.rpm文件
-bb build binary,只做成rpm文件
-bs build source,只做成srpm文件

创建rpm成功后,会默认清空BUILDROOT目录,如果再加上--noclean选项,则会保留,便于进行调试。

本例的完整结构如下,可以对照查看:

复制代码
├── BUILD
│   └── cello-1.0
│       ├── cello
│       ├── cello.c
│       ├── cello.conf
│       ├── debugfiles.list
│       ├── debuglinks.list
│       ├── debugsources.list
│       ├── elfbins.list
│       ├── Makefile
│       └── README.md
├── BUILDROOT
│   └── cello-1.0-1.el7.x86_64
│       ├── etc
│       │   └── cello
│       │       └── cello.conf
│       └── usr
│           ├── bin
│           │   └── cello
│           ├── lib
│           │   └── debug
│           │       └── usr
│           │           └── bin
│           │               └── cello.debug
│           ├── share
│           │   └── doc
│           │       └── cello-1.0
│           │           └── README.md
│           └── src
│               └── debug
│                   └── cello-1.0
│                       └── cello.c
├── RPMS
│   └── x86_64
│       ├── cello-1.0-1.el7.x86_64.rpm
│       └── cello-debuginfo-1.0-1.el7.x86_64.rpm
├── SOURCES
│   ├── cello-1.0.tar.gz
│   └── cello-patch.patch
├── SPECS
│   └── cello.spec
└── SRPMS

3.5 安装rpm包

构建完成后,可以用:

  • rpm -ivh xxx.rpm:安装rpm包
  • rpm -qa:查看已安装的rpm包
  • rpm -e xxx.rpm:卸载rpm包

卸载rpm包时,如果%preun或者%postun写的不正确,会出现无法卸载的情况,此时可以加上--noscripts跳过两个阶段强制卸载,相应的残留文件需要手工删除

3.6 使用src.rpm包

src.rpm包也可以使用rpm -ivh命令安装,但是并不会实际安装软件,而是解压出源代码压缩包、补丁、spec文件以及其他普通文件。网络资料显示源代码会接到到 /usr/src/redhat/ 或 /usr/src/packages/ 目录下,但是实际文件出现在了~/rpmbuild/目录下。

也可以使用rpm2cpio package.src.rpm | cpio -idmv命令将源代码接到到当前目录下。

笔记

常用宏

含义 示例
% 无条件宏展开:如果宏已定义,则替换为对应值;如果未定义,则报错。多为用户自定义宏或非路径类系统宏 %
% 无条件展开。以下划线开头,通常为系统预定义的路径宏,用于表示标准目录或系统环境变量 %{_bindir} → 展开为/usr/bin
% 当宏已定义且非空时展开为x,否则替换为空字符串 %{?alphatag:%{?alphatag}.},如果alphatag已定义,则展开
% 当宏未定义时执行冒号后的操作 %{!?build_agent: %global build_agent 1},如果build_agent未定义,则全局置为1

常用Body Items

Body Items 含义
%package 定义子包,。当需要从一个 spec 文件生成多个 RPM 包时,可通过%package声明子包并设置其独立属性
相关推荐
争取不加班!2 年前
GitLab-访问返回403 forbidden问题处理
运维·git·gitlab·问题排查·linxu