当前位置: 首页 > news >正文

【Linux】从零开始:RPM 打包全流程实战万字指南(含目录结构、spec 编写、分步调试)

引言

        RPM(Red Hat Package Manager)文件是一种用于Linux系统的软件包管理格式,主要用于基于Red Hat的Linux发行版,如Fedora、CentOS和Redhat等。一个RPM软件包实际上是一个包含了已编译的软件以及有关该软件的元数据(如名称、版本号、依赖关系等)的压缩归档文件。

目录

引言

一、环境准备

二、RPM文件的组成

1、根据RPM的目录结构分类

2、根据RPM文件内容分类

三、SPEC文件

1、SPEC 文件结构

2、SPEC 文件语法

3、SPEC模板创建

4、SPEC文件示例

四、完整打包流程

1、准备自己的布局文件

2、创建RPM目录结构

3、将源文件放入SOURCES目录

4、SPEC文件

5、生成RPM包

6、测试验证

五、高级调试与优化

1、分步调试

2、依赖分析

3、构建问题诊断

 4、依赖分析工具

 5、质量检查

6、性能优化技巧

六、应用场景

参考


一、环境准备

  RPM 包构建需要依赖rpmdevtools工具包,安装命令如下。

# 安装必要工具
sudo yum install rpmdevtools rpmlint rpmdev-setuptree
  • rpmdevtools:一个工具包,包含多个命令,帮你方便地制作 RPM 软件包。其中就包括 rpmdev-setuptree
  • rpmdev-setuptree:是 rpmdevtools 里的一个命令,运行它会自动在你家目录下创建好打包所需的文件夹结构(如 ~/rpmbuild/SPECS~/rpmbuild/SOURCES 等)。
  • rpmlint:一个检查工具。用来检查你的 RPM 包或 .spec 文件有没有错误或不符合规范的地方,确保打包质量。

二、RPM文件的组成

1、根据RPM的目录结构分类

~/rpmbuild/
├── BUILD/      # %prep 阶段会在这里解压源码,%build 和 %install 阶段也在此目录操作
├── BUILDROOT/  # 临时安装根目录,%install 阶段会把编译好的文件“安装”到这里RPM 打包时从这收集
├── RPMS/       # 存放最终生成的 二进制 RPM 包,通常按架构(如 x86_64, aarch64)分目录存放
├── SOURCES/    # 存放所有原始材料:源码压缩包(如 .tar.gz)、补丁文件、图标、配置文件等
├── SPECS/      # 存放 .spec 文件,这是 RPM 构建的“配方”,定义了如何准备、编译、安装和打包软件
└── SRPMS/      # 存放生成的源码 RPM 包(.src.rpm)

2、根据RPM文件内容分类

1)文件系统布局文件 (Payload)

  • 二进制可执行文件:/usr/bin/,/usr/local/bin等

  • 依赖库文件:/usr/lib/,/usr/lib64

  • 配置文件:/etc/ (带有%config标记)

  • 文档文件:/usr/share/doc/

  • 元数据:SPEC文件、changelog、依赖信息

  • 脚本钩子:pre/post install/uninstall脚本

2)元数据 (Metadata):

  • SPEC 文件: 这是构建 RPM 的“菜谱”,包含了构建指令、文件列表、依赖关系、脚本、变更日志等所有信息。

  • 依赖信息:

    • Requires: 该 RPM 包运行时依赖的其他包(或库、文件等)。

    • Provides: 该 RPM 包提供的能力(通常是包名本身,但也可能是虚拟能力如 webserver 或库的 soname)。

    • Conflicts: 与该 RPM 包冲突不能同时安装的其他包。

    • Obsoletes: 该 RPM 包会取代(并通常卸载)的其他旧包。

    • BuildRequires: 构建该 RPM 包所需的依赖(编译器、库等)。

  • 变更日志 (%changelog): 记录包版本更新历史的条目。这个信息会包含在生成的 .rpm 文件中,可以用 rpm -q --changelog查看。

  • 其他元数据: 包名、版本号、发行号 (Release)、架构 (Arch)、摘要 (Summary)、描述 (Description)、打包者 (Packager)、供应商 (Vendor)、许可证 (License)、URL 等。这些信息都存储在 RPM 头部 (Header) 中。

3)脚本钩子 (Scriptlets):

  • %pre: 在安装包之前运行的脚本。

  • %post: 在安装包之后运行的脚本(常用于更新 ldconfig, 初始化数据库,启动服务)。

  • %preun: 在卸载包之前运行的脚本(常用于优雅地停止服务)。

  • %postun在卸载包之后运行的脚本(常用于清理 ldconfig 缓存,删除空目录)。

  • %pretrans / %posttrans在事务(可能涉及多个包的安装/卸载)开始前/结束后运行的脚本(更复杂,较少用)。

rpmbuild 目录是“厨房”,SPEC 是“菜谱”,SOURCES 是“食材”,RPMS 是“做好的菜”,而 RPM 包本身是“带标签的密封餐盒”,里面装着菜(文件)和说明书(元数据)。

三、SPEC文件

       SPEC 文件是创建自定义RPM包的基础。它是一个文本文件,定义了如何从源代码构建RPM包。包括了软件的名称、版本、发布信息、构建指令、安装指令、描述、依赖关系等信息。

        SPEC 文件是源码,不是 RPM 二进制包的一部分。它本身并不包含在生成的 .rpm 文件中。.rpm 文件包含的是 SPEC 文件编译后的结果。

1、SPEC 文件结构

# 基础元数据 (Basic Metadata)
Name:    package-name     # 包名(全小写,无空格)
Version: 1.0.0            # 上游版本号
Release: 1%{?dist}        # 打包版本号(每次打包递增)
Summary: 单行描述         # 30字以内摘要
License: GPLv3+           # 许可证(SPDX格式)# 高级元数据 (Advanced Metadata)
URL:     https://project.org  # 项目主页
Vendor:  Company Name         # 供应商信息
Group:   Development/Tools    # 分类(兼容旧系统)
Source0: %{name}-%{version}.tar.gz  # 源码URL/路径
Patch1:  fix-security.patch   # 补丁文件

2、SPEC 文件语法

  • 宏变量

    • %{name}%{version} 自动填充

    • %{?dist} 处理发行版后缀

    • %{_bindir}%{_libdir} 等路径宏

  • 构建阶段

    • %prep准备源码

    • %build编译源码

    • %install安装到构建根目录

    • %check运行测试

  • 脚本钩子

    • %pre/%post安装前后脚本

    • %preun/%postun卸载前后脚本

    • %posttrans事务后操作

  • 多包支持

    • 使用 %package 定义子包

    • %description -n subpackage 子包描述

    • %files -n subpackage 子包文件列表

3、SPEC模板创建

  • 通用模板
rpmdev-newspec -o ~/rpmbuild/SPECS/myapp.spec
  • 标准 C/C++ 项目模板
rpmdev-newspec -t lib ~/rpmbuild/SPECS/mylibrary.spec
  • python项目模板
rpmdev-newspec -t python ~/rpmbuild/SPECS/mypythonapp.spec
  • systemd服务模板
rpmdev-newspec -t service ~/rpmbuild/SPECS/mydaemon.spec

4、SPEC文件示例

# ===================================================================
# RPM SPEC 文件通用模板 (优化版)
# 适用于大多数基于源码构建的软件包
# 遵循 Fedora 打包规范和最佳实践
# 注意:根据实际项目替换占位符(如 %{name}, %{version} 等)
# ===================================================================%global _enable_debug_package 0    # 禁用 debuginfo 包(按需开启)
%global _hardened_build 1          # 启用安全加固编译Name:           your-package-name
Version:        1.0.0
Release:        1%{?dist}
Summary:        A brief description of the package (少于 80 字符)# 使用 SPDX 许可证标识符 (https://spdx.org/licenses/)
License:        MIT
URL:            https://github.com/yourusername/your-package-name
Source0:        %{url}/archive/v%{version}/%{name}-%{version}.tar.gz# 构建架构(默认自动检测,noarch 适用于脚本/解释型语言)
# BuildArch:      noarch# 构建依赖(使用宏确保兼容性)
BuildRequires:  gcc
BuildRequires:  make
BuildRequires:  pkgconfig
BuildRequires:  systemd-rpm-macros
BuildRequires:  %{?_python:python%{python_version}-devel}  # Python 项目示例# 运行时依赖(自动依赖检测 + 显式声明)
Requires:       bash >= 4.2
Requires:       coreutils
Requires:       systemd# 提供虚拟能力(如需要)
Provides:       bundled(openssl) = 1.1.1k   # 示例:声明捆绑的库
Provides:       %{name}-cli = %{version}    # 子包提供%description
A longer description of the package.
Explain what it does, who it's for, and any special features.
This can span multiple lines.%prep
%autosetup -n %{name}-%{version} -p1  # 自动处理源码和补丁
# 示例补丁应用:
# %patch0 -p1 -b .buildfix  # 应用补丁并备份原文件%build
%set_build_flags  # 设置标准构建标志(CFLAGS/LDFLAGS)# === 根据构建系统选择 ===
# 1. Autotools 项目
%configure \--disable-static \     # 推荐禁用静态库--enable-shared \--with-systemd \--without-debugmake %{?_smp_mflags} VERBOSE=1# 2. CMake 项目
# %cmake \
#     -DCMAKE_BUILD_TYPE=Release \
#     -DENABLE_TESTS=OFF \
#     -DINSTALL_DOCS=ON
# 
# %cmake_build %{?_smp_mflags}# 3. 纯 Makefile 项目
# make %{?_smp_mflags} \
#     CC="%{__cc}" \
#     CFLAGS="%{optflags}" \
#     LDFLAGS="%{__global_ldflags}"%install
# 清理并创建必要目录
rm -rf %{buildroot}
%make_install                # 适用于 make install 项目# === 手动安装示例 ===
# 1. 安装可执行文件
install -d -m 0755 %{buildroot}%{_bindir}
install -m 0755 %{name} %{buildroot}%{_bindir}/# 2. 配置文件 (noreplace 防止覆盖用户修改)
install -d -m 0755 %{buildroot}%{_sysconfdir}/%{name}
install -m 0644 config.conf %{buildroot}%{_sysconfdir}/%{name}/%{name}.conf# 3. Systemd 服务文件
install -d -m 0755 %{buildroot}%{_unitdir}
install -m 0644 %{name}.service %{buildroot}%{_unitdir}/# 4. 文档和许可证
%license LICENSE
%doc README.md CHANGELOG.md CONTRIBUTING.md# 5. 创建运行时目录
install -d -m 0755 %{buildroot}%{_sharedstatedir}/%{name}
install -d -m 0755 %{buildroot}%{_localstatedir}/log/%{name}%check
# 构建后测试(确保 BuildRequires 包含测试依赖)
# make test
# 或 ctest -V
# 或 pytest%post
# 系统用户/组管理
getent group %{name} >/dev/null || groupadd -r %{name}
getent passwd %{name} >/dev/null || \useradd -r -g %{name} -d %{_sharedstatedir}/%{name} \-s /sbin/nologin -c "%{name} service user" %{name}# 设置目录权限
chown -R %{name}:%{name} %{_sharedstatedir}/%{name}
chown -R %{name}:%{name} %{_localstatedir}/log/%{name}# 服务管理
%systemd_post %{name}.service%preun
%systemd_preun %{name}.service%postun
%systemd_postun_with_restart %{name}.service%posttrans
# 数据库迁移等事务后操作
if [ $1 -eq 1 ] || [ $1 -ge 2 ]; then  # 安装或升级后/usr/bin/%{name}-db-migrate
fi%files -f %{name}.lang  # 如果有多语言文件
%license LICENSE
%doc README.md CHANGELOG.md
%dir %{_sysconfdir}/%{name}               # 配置目录
%config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf  # 配置文件
%{_bindir}/%{name}                        # 主程序
%{_unitdir}/%{name}.service               # systemd 服务
%{_mandir}/man1/%{name}.1.gz              # 手册页
%dir %{_sharedstatedir}/%{name}           # 数据目录
%ghost %{_localstatedir}/log/%{name}      # 日志目录(不打包内容)# === 子包示例 ===
%package devel
Summary:        Development files for %{name}
Requires:       %{name}%{?_isa} = %{version}-%{release}%description devel
Headers and libraries for developing applications that use %{name}%files devel
%{_includedir}/%{name}.h
%{_libdir}/lib%{name}.so
%{_libdir}/pkgconfig/%{name}.pc%changelog
* %(date +"%a %b %d %Y") Your Name <you@example.com> - 1.0.0-1
- 初始版本打包# 使用自动化工具生成 changelog:
# rpmdev-bumpspec --comment="更新说明" --user="Your Name <email>" SPECS/%{name}.spec

四、完整打包流程

这里为了方便, 通过一个具体的例子演示。

开发环境:Linux Centos 6.12.0-105.el10.x86_64 GNU/Linux

1、准备自己的布局文件

1)新建一个工程文件夹,如my_test。

mkdir my_test

2)创建一个myTest.c文件,内容为打印一下“hello world”。

//myTest.c文件
#include <stdio.h>int main(){printf("hello world!\n");return 0;
}

3)为myTest.c写一个Makefile用来编译

#Makefile文件
myTest: myTest.cgcc myTest.c -o myTest
clean:rm myTest

4)测试验证程序

提示:打包前一定要测试基本程序的正确性,这是一个好习惯!

#编译及测试验证
[root@Centos my_test]# make
gcc myTest.c -o myTest
[root@Centos my_test]# ./myTest
hello world!
[root@Centos my_test]# make clean
rm myTest
[root@Centos my_test]# ls
Makefile  myTest.c

2、创建RPM目录结构

#创建rpm目录结构
rpmdev-setuptree#查看rpm目录结构
tree rpmbuild/#显示结果
# rpmbuild/
# ├── BUILD
# ├── RPMS
# ├── SOURCES
# ├── SPECS
# └── SRPMS

3、将源文件放入SOURCES目录

#将工程文件压缩打包,并放进rpmbuild/SOURCES目录下
tar czvf ~/rpmbuild/SOURCES/my_test.tar.gz my_test#结果显示:
#my_test/
#my_test/myTest.c
#my_test/Makefile

4、SPEC文件

1)直接生成一个通用SPEC模板

rpmdev-newspec -o ~/rpmbuild/SPECS/myTest.spec#结果:/root/rpmbuild/SPECS/myTest.spec created; type minimal, rpm version >= 4.19.

2)修改SPEC文件

修改内容:Version、Source0路径、添加%files部分等;

修改后的完整SPEC文件内容:

# 禁用 debuginfo 包生成
%global debug_package %{nil}Name:           myTest
Version:        1.0.0
Release:        1%{?dist}
Summary:        A simple C language test program
License:        MIT
URL:            https://github.com/yourusername/myTest
Source0:        myTest-1.0.0.tar.gz
BuildRequires:  gcc%description
A simple C language test program.%prep
#下面setup是解压压缩包, -n myTest-%{version}是指定解压后的文件夹名称, -q是不显示过程信息
%setup -n myTest-%{version} -q%build
make%install
# buildroot是搭建一个虚拟的文件系统目录,  _bindir 等价 /usr/bin
rm -rf %{buildroot}
mkdir -p %{buildroot}%{_bindir}
cp myTest %{buildroot}%{_bindir}/myTest%files
%{_bindir}/myTest%changelog
* Fri Aug 08 2025 Super User <user@example.com> - 1.0.0-1
- Initial build

5、生成RPM包

如果上面步骤都没问题,那么直接执行下面就会生成rpm包了。

rpmbuild -ba ~/rpmbuild/SPECS/myTest.spec

成功后会在RPMS下生成最终的目标RPM包。

[root@Centos ~]# tree rpmbuild/#显示结果:
#rpmbuild/
#├── BUILD
#├── BUILDROOT
#├── RPMS
#│   └── x86_64
#│       └── myTest-1.0.0-1.el10.x86_64.rpm   #这就是目标RPM包
#├── SOURCES
#│   └── myTest-1.0.0.tar.gz
#├── SPECS
#│   └── myTest.spec
#└── SRPMS
#    └── myTest-1.0.0-1.el10.src.rpm

生成时如遇到问题时非常正常的,需要一步一步的调试优化,最终达到效果。

下一章会介绍一些调试和优化的方法。

6、测试验证

1)验证是否安装成功

[root@Centos ~]# rpm -ql myTest#成功显示已安装的文件,如下:
#/usr/bin/myTest
#/usr/lib/.build-id
#/usr/lib/.build-id/3c
#/usr/lib/.build-id/3c/3412eaf27ce1deb57e230a1a4fb7c2191a945e

2)测试程序是否可以使用

[root@Centos ~]# myTest
hello world!  #在任意目录下执行  myTest =, 都可以打印“hello world”

五、高级调试与优化

1、分步调试

rpmbuild 分步调试是排查打包问题的 最有效方法。通过逐步执行 .spec 文件中的各个阶段,你可以精准定位问题出在哪个环节。

RPM打包会按照SPEC文件的配置顺序执行,如果有错误会在终端提示。根据提示信息,我们可以使用对应的命令单步调试,修改SPEC阶段命令。

阶段命令说明
%preprpmbuild -bp准备:解压源码、打补丁
%buildrpmbuild -bc编译:运行 make 等
%installrpmbuild -bi安装:复制文件到 BUILDROOT
%checkrpmbuild -bt测试(可选)
打包rpmbuild -bb构建二进制 RPM
全流程rpmbuild -ba从头到尾构建

2、依赖分析

# 检查未打包文件
find %{buildroot} -type f | grep -vFf <(rpm -qlp app.rpm)# 依赖分析
rpm -qpR app.rpm # 查看依赖

3、构建问题诊断

# 详细构建日志
rpmbuild -ba --define='_verbose 10' package.spec 2>&1 | tee build.log# 检查未打包文件
find %{buildroot} -type f | grep -vFf <(rpm -qlp package.rpm)

 4、依赖分析工具

# 生成依赖图
rpm -qpR package.rpm | xargs rpmdep -o deps.dot
dot -Tpng deps.dot -o deps.png# 或使用rpmlint自动检测缺失依赖
rpmlint -i package.spec

 5、质量检查

​​​​​​​# SPEC 文件检查
rpmlint SPECS/%{name}.spec# RPM 包检查
rpmlint RPMS/x86_64/%{name}-*.rpm

6、性能优化技巧

# 并行编译
%define _smp_mflags -j%(nproc)# 编译缓存
%define _ccache_path /usr/bin/ccache
export CCACHE_DIR="/var/cache/ccache"

六、应用场景

  • 打包复杂的企业级应用
  • 设计自动化的构建流水线
  • 处理多架构兼容性问题
  • 实现安全的软件分发流程
  • 解决依赖地狱问题

参考

  • RPM 官方网站 https://rpm.org/

  • man rpm
http://www.dtcms.com/a/321778.html

相关文章:

  • 【探展WAIC】从“眼见为虚”到“AI识真”:如何用大模型筑造多模态鉴伪盾牌
  • 惯量时间常数 H 与转动惯量 J 的关系解析
  • uniapp开发微信小程序遇到富文本内容大小变形问题v-html
  • 【谷歌 SEO】排查页面未索引问题:原因与解决方案
  • 页面tkinter
  • CALL与 RET指令及C#抽象函数和虚函数执行过程解析
  • 锂电池保护板测试仪:守护电池安全的核心工具|深圳鑫达能
  • 深度学习里一些常用的指标(备份)
  • 常见数据结构介绍(顺序表,单链表,双链表,单向循环链表,双向循环链表、内核链表、栈、队列、二叉树)
  • 浅析线程池工具类Executors
  • 客户端攻击防御:详解现代浏览器安全措施
  • Python字典高阶操作:高效提取子集的技术与工程实践
  • Socket编程预习
  • js 实现洋葱模型、洋葱反向模型
  • 关于 Rust 异步(无栈协程)的相关疑问
  • Prometheus 监控平台部署与应用
  • 新版速递|ColchisFM突破传统建模局限,用地质统计学模拟构建更真实的地震正演模型
  • 1635. 预算够吗
  • linux运维命令查看cpu、内存、磁盘使用情况
  • FFmpeg 编译安装和静态安装
  • 12、GPIO介绍
  • Redis7集群搭建与原理分析
  • element plus table 表格操作列根据按钮数量自适应宽度
  • 从引导加载程序到sysfs:Linux设备树的完整解析与驱动绑定机制
  • 您与此网站之间建立的连接不安全
  • 智慧园区漏检率↓82%:陌讯多模态融合算法实战解析
  • 防御保护09
  • 【从0到1制作一块STM32开发板】6. PCB布线--信号部分
  • 手机拍照识别中模糊场景准确率↑37%:陌讯动态适配算法实战解析
  • 二、k8s 1.29 之 网络