news 2026/4/15 10:56:39

使用rpmbuild将源代码制成rpm包

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用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文件主要构成有:

Preamble Items

包含了包的元数据,这些项可以作为宏在spec文件中使用,以提高文件的可移植性。

关键字 说明

Name 包的名称

Version 包的版本

Release release版本

Summary 简要说明

License 遵循的License

Source0 使用的源代码包,如果有多个可以有Source1、 Source2……,由于使用了宏,替换后这里的源代码包即为cello-1.0.tar.gz

Patch0 使用的补丁,可以有多个:Patch1、Patch2……

BuildRequires build时需要的包

Requires 运行时需要的包,本例中无

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,因此需要删除

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声明子包并设置其独立属性

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/14 20:05:42

TextGrid Repository论文解读:人文研究数据保存的流畅化工作流程

流畅化出版工作流程&#xff1a;使用TextGrid Repository保存人文研究数据 作者单位 (1) 哥廷根大学 (2) 德累斯顿工业大学 (3) 马克斯韦伯基金会 - 德国海外人文科学研究所 (4) 哥廷根科学数据处理协会 摘要 英文摘要&#xff1a;本文介绍了TextGrid Repository中文本研究…

作者头像 李华
网站建设 2026/4/8 17:03:35

文献综述:不确定性时代的传播学研究——理论重构与实践转向

文献综述&#xff1a;不确定性时代的传播学研究——理论重构与实践转向 研究概述 21世纪以来&#xff0c;全球社会经历了前所未有的动荡与变革。健康危机、生态崩溃、地缘政治紧张、经济转型、大规模移民、信息战以及极端主义抬头等一系列重大事件&#xff0c;标志着世界正处于…

作者头像 李华
网站建设 2026/4/13 14:10:41

什么是单例模式?

例模式是一种创建型设计模式&#xff0c;它确保一个类只有一个实例&#xff0c;并提供一个全局访问点来获取这个实例。在 TypeScript 中&#xff0c;单例模式特别有用&#xff0c;因为它结合了 JavaScript 的灵活性和 TypeScript 的类型安全。为什么需要单例模式&#xff1f;想…

作者头像 李华
网站建设 2026/4/7 16:02:11

【JavaWeb】ServletContext_域对象相关API

域对象的相关API 域对象&#xff1a;一些用于存储数据和传递数据的对象&#xff0c;传递数据不同的范围&#xff0c;我们称之为不同的域&#xff0c;不同的域对象代表不同的域&#xff0c;共享数据的范围也不同ServletContext代表应用&#xff0c;所以ServletContext域也叫作应…

作者头像 李华
网站建设 2026/4/12 13:51:12

从混沌到秩序:Apache Airflow 3.0构建智能数据管道的架构演进与实践方案

从混沌到秩序&#xff1a;Apache Airflow 3.0构建智能数据管道的架构演进与实践方案 【免费下载链接】airflow Airflow 是一款用于管理复杂数据管道的开源平台&#xff0c;可以自动执行任务并监控其状态。高度可定制化、易于部署、支持多种任务类型、具有良好的可视化界面。灵活…

作者头像 李华