RPM打包
禁止自动分析源码添加不应该加入的依赖 在spec文件中加入Autoreq: 0即可
opnvswitch源码打包需要加入,否则会解析代码中的依赖,在ISO中安装检测失败/bin/python3
%post 部分如果有shell 则依赖关系会自动增加/bin/sh , 如果合并入镜像是不能有/bin/sh /bin/python等
一、打包工具安装
执行命令安装所需的rpm包:
yum install rpmdevtools rpmlint make gcc -y
rpmdevtools包里包括了rpmbuild ,安装好工具后,使用命令rpmdev-setuptree
生成~/rpmbuild目录及其子目录
tree rpmbuild
rpmbuild ├── BUILD ├── RPMS ├── SOURCES ├── SPECS └── SRPMS
或者手动生成目录,命令如下:
mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
Fedora的文档建议不使用root用户进行RPM打包
二、使用spec文件创建rpm包
切换路径至SPECS文件夹,使用命令创建spec文件(rpm打包的脚本规则文件),执行命令
rpmdev-newspec myrpm
在当前目录生成了myrpm.spec文件,内容如下(增加了说明和其他部分,源文件比较简单)
Name: myrpm Version: Release: 1%{?dist} Summary: License: # GPLBSDMITor URL: Source0: SOURCES/%{name}-%{version}.tar.gz BuildRequires: # rpm Requires: # rpm -ivh %description # %prep # %prep %setup -q SOURCES${Source0} BUILD %{name}-%{version} %setup -q # %patch0 -p1 %build # %build %build # cdBUILD/%{name}-%{version}() %configure # %configureconfigureautoconfconfigure , make %{?_smp_mflags} # %{_smp_mflags} cpuCPUmake , ~/.rpmmacros %install # %install # BUILD/%{name}-%{version}() # BUILDROOTBUILDROOT rm -rf $RPM_BUILD_ROOT #BUILDROOTcentos6 $RPM_BUILD_ROOT %{buildroot} BUILDROOT/%{name}-%{version}-%{release}.%{_arch} %make_install # %make_installmake install %clean #RPMBUILD rm -rf %{buildroot} %files # BUILDROOT/package/ , /usr/bin/test %config(noreplace) %{_sysconfdir}/foo.conf # *.rpmsave *.rpmnew %config %{_sysconfdir}/foo.conf # /etc %attr(755, root, root) %{_sysconfdir}/foo.conf %attr(mode, user, group) %{_sysconfdir}/foo.conf # ”-” /usr/bin/test %doc %changelog ## rpm -q package --changelog
开始部分里开头是大写字母的字段,可以被当做变量引用 %{name} %{version} %{release} ...
rpmlint xx.spec可以检测spec语法正确性
spec 中不需要的部分直接删除即可
%build和%install部分都是先cd到BUILD/包名的目录下, 在执行其他命令
三、 SPEC规则注解
rpmbuild ├── BUILD ├── BUILDROOT ├── RPMS ├── SOURCES ├── SPECS └── SRPMS
rpmdev-setuptree 执行完之后缺少一个BUILDROOT目录, 实际执行 还要用到该目录, 但不需手动创建,在rpmbuild的过程中会 自动创建。
rpmbuild的规则里有一些内置宏变量,以%开头的, 查看方法rpmbuild --showrc 或者rpm --showrc 几种方式都可以查看;
要查看具体某个宏的值可以使用rpm --eval/-E , 比如 (规范宏写法应该是%{_name})
$ rpm -E %{_topdir} /home/wanglin/rpmbuild
路径 | 宏 | 名称 | 用途 |
---|---|---|---|
~/rpmbuild/BUILD | %_builddir | 构建目录 | 源代码包从SOURCES目录解压缩后放到该目录,并在该目录进行编译即configure 和 make命令 |
~/rpmbuild/BUILDROOT | %_buildrootdir | 最终安装目录 | 保存%install阶段安装的文件,即make install执行后产生的文件 |
~/rpmbuild/RPMS | %_rpmdir | 标准rpm包目录 | 生成的二进制rpm包会存放在该目录 |
~/rpmbuild/SOURCES | %_sourcedir | 源代码目录 | 源码tar.gz包放到该目录 |
~/rpmbuild/SPECS | %_specdir | Spec文件目录 | Spec文件存放路径 |
~/rpmbuild/SRPMS | %_srcrpmdir | 源码RPM包目录 | 生成的srpm包存放在该目录 |
四、spec中的脚本
脚本片段 类似kickstart文件,使用shell编写
- %pre: 在rpm包安装之前执行
- %post: 在安装rpm包之后执行
- %preun: 在卸载rpm包之前执行
- %postun: 在卸载rpm包之后执行
- %pretrans: 在事务开始时执行
- %posttrans: 在事务结束时执行
通常所有安装脚本和触发器脚本都是使用 /bin/sh 来执行的,如果想使用其他脚本,如 perl,可使用 -p /usr/bin/perl 来告诉 rpm 使用perl解释器
如果仅执行一个命令,则 “-p” 选项会直接执行,而不启用 shell。然而,若有许多命令时,不要使用此选项,按正常编写 shell 脚 本即可。
%pre、%post、%preun 和 %postun 提供 1 的值恒为 0。
- | install | upgrade | uninstall |
---|---|---|---|
%pretrans | $1 == 0 | $1 == 0 | (N/A) |
%pre | $1 == 1 | $1 == 2 | (N/A) |
%post | $1 == 1 | $1 == 2 | (N/A) |
%preun | (N/A) | $1 == 1 | $1 == 0 |
%postun | (N/A) | $1 == 1 | $1 == 0 |
%posttrans | $1 == 0 | $1 == 0 | (N/A) |
示例1:
%post if [ "$1" = 1 ]; then $1 == 0 $1 == 2 $1 == 2 $1 == 1 $1 == 1 $1 == 0 (N/A) (N/A) (N/A) $1 == 0 $1 == 0 (N/A) # rpm1 if if [ ! -f %{_sysconfdir}/shells ] ; then echo "%{_bindir}/foo" > %{_sysconfdir}/shells echo "/bin/foo" >> %{_sysconfdir}/shells else grep -q "^%{_bindir}/foo$" %{_sysconfdir}/shells || echo "%{_bindir}/foo" >> %{_sysconfdir}/shells grep -q "^/bin/foo$" %{_sysconfdir}/shells || echo "/bin/foo" >> %{_sysconfdir}/shells fi %postun #0 if [ "$1" = 0 ] && [ -f %{_sysconfdir}/shells ] ; then sed -i '\!^%{_bindir}/foo$!d' %{_sysconfdir}/shells sed -i '\!^/bin/foo$!d' %{_sysconfdir}/shells fi
示例2:
例如,如果软件包安装了一份 info 手册,那么可以用 info 包提供的 install-info 来更新 info 手册索引。 首先,我们不保证系统已安装 info 软件包,除非明确声明需要它;其次,我们不想在 install-info 执行失败时,使软件包安装失败:
Requires(post): info Requires(preun): info ... %post /sbin/install-info %{_infodir}/%{name}.info %{_infodir}/dir || : %preun if [ $1 = 0 ] ; then /sbin/install-info --delete %{_infodir}/%{name}.info %{_infodir}/dir || : fi
上边的示例中还有一个安装 info 手册时的小问题需要解释一下。install-info 命令会更新 info 目录,所以我们应该在 %install 阶段删 除 %{buildroot} 中无用的空目录:
rm -f %{buildroot}%{_infodir}/dir
一般最后一条命令的exit状态就是脚本的exit状态,除一些特殊情况,一般脚本都是以exit 0状态退出所以大部分脚本片段都会使用 "||:" 退出
五、执行打包命令生成rpm
SPEC 编写完毕,执行以下命令来构建 SRPM 和 RPM 包:
rpmbuild -ba myrpm.spec
如果成功,RPM 会保存至 ~/rpmbuild/RPMS,SRPM 会保存至 ~/rpmbuild/SRPMS。
如果失败,请查看 BUILD 目录的相应编译日志。为了帮助调试,可以用 --short-circuit 选项来忽略成功的阶段。例如,若想要(略过更早的阶段)重新从 %install 阶段开始,请执行:
rpmbuild -bi --short-circuit myrpm.spec
如果只想创建 RPM,请执行:
rpmbuild -bb myrpm.spec
如果只想创建 SRPM(不需要执行 %prep 或 %build 或其他阶段),请执行:
rpmbuild -bs myrpm.spec
rpmlint检查
为避免常见错误,请先使用 rpmlint 查找 SPEC 文件的错误:
rpmlint program.spec
如果返回错误/警告,使用 “-i” 选项查看更详细的信息。
也可以使用 rpmlint 测试已构建的 RPM 包,检查 SPEC/RPM/SRPM 是否存在错误。你需要在发布软件包之前,解决这些警告。此 页面 提供一些常见问题的解释。如果你位于 SPEC 目录中,请执行:
rpmlint myrpm.spec ../RPMS/*/NAME*.rpm ../SRPMS/NAME*.rpm
进入 ~/rpmbuild/RPMS 下的特定架构目录中,您会发现有许多二进制 RPM 包。使用以下命令快速查看 RPM 包含的文件和权限:
rpmls *.rpm
六、部分宏变量
%{_sysconfdir} /etc %{_prefix} /usr %{_exec_prefix} %{_prefix} %{_bindir} %{_exec_prefix}/bin %{_libdir} %{_exec_prefix}/%{_lib} %{_libexecdir} %{_exec_prefix}/libexec %{_sbindir} %{_exec_prefix}/sbin %{_sharedstatedir} /var/lib %{_datarootdir} %{_prefix}/share %{_datadir} %{_datarootdir} %{_includedir} %{_prefix}/include %{_infodir} /usr/share/info %{_mandir} /usr/share/man %{_localstatedir} /var %{_initddir} %{_sysconfdir}/rc.d/init.d %{_var} /var %{_tmppath} %{_var} /tmp %{_usr} /usr %{_usrsrc} %{_usr}/src %{_lib} lib (lib64 on 64bit multilib systems) %{_docdir} %{_datadir}/doc %{buildroot} %{_buildrootdir}/%{name}-%{version}-%{release}.%{_arch} $RPM_BUILD_ROOT %{buildroot} %{_unitdir} /usr/lib/systemd/system %define Macro Value Macro=Value
七、一个只打包文件的spec实例
Name: cvk_tools Version: 1.1 Release: 1%{?dist} Summary: cvk_tools by wanglin License: GPLv3 URL: Source: %{name}-%{version}.tar.gz BuildArch: %{_arch} Autoreq: 0 %prep %setup -q %description init cvk %define pack_path root/%{name}-%{version} %define ca_path etc/pki/CA %install install -d %{buildroot}/%{pack_path} install -d %{buildroot}/%{ca_path} for i in `ls ./`;do if [ -f $i ];then install ./$i %{buildroot}/%{pack_path} elif [ -d $i ];then if [[ $i =~ "ca" ]];then install -m 444 -o root -g root ./ca/cacert.pem %{buildroot}/%{ca_path} else install -d %{buildroot}/%{pack_path}/$i for f in `ls $i`;do install $i/$f %{buildroot}/%{pack_path}/$i done fi fi done # Upgarde${conf}.old %pre conf=/%{pack_path}/tools.conf if (( $1 == 2 ));then [ -f $conf ] && mv $conf ${conf}.old || : fi # Upgrade %post conf=/%{pack_path}/tools.conf if (( $1 == 2 ));then [ -f ${conf}.old ] && mv ${conf}.old ${conf} || : fi %postun if (( $1 == 0 ));then [ -d /%{ca_path} ] && rm -rf /%{ca_path} || : [ -d $(dirname /%{ca_path}) ] && rm -rf $(dirname /%{ca_path}) || : [ -d /%{pack_path} ] && rm -rf /%{pack_path} || : fi %files %attr(-, root, root) # first method /%{pack_path} /%{ca_path} #----second method #%dir /%{pack_path} #/%{pack_path}/* #%dir /%{ca_path} #/%{ca_path}/* %doc %changelog * Fri Jul 1 2022 cvk_tools Release - 1.1-1 - Second Version release * Thu Nov 25 2021 cvk_tools Release - 1.0-1 - Initial first version
附录: 打包遇到的问题
- fle段缺少文件
Checking for unpackaged file(s): /usr/lib/rpm/check-files /root/rpmbuild/BUILDROOT/lldpad-1.1-1.el7.x86_64 error: Installed (but unpackaged) file(s) found: /usr/etc/bash_completion.d/lldpad /usr/etc/bash_completion.d/lldptool /usr/include/lldpad/clif.h /usr/include/lldpad/clif_msgs.h /usr/include/lldpad/clif_sock.h ... RPM build errors: Installed (but unpackaged) file(s) found: /usr/etc/bash_completion.d/lldpad /usr/etc/bash_completion.d/lldptool /usr/include/lldpad/clif.h /usr/include/lldpad/clif_msgs.h /usr/include/lldpad/clif_sock.h ...
这个意思是说发现了制作RPM包的spec脚本中没有包含但又被安装的文件
如果显示很多文件,将这些文件你可以分门别类,用%doc、%config这些宏来指定,其实如果它报错的时候,只显示一两个文件,可 以直接把那个文件写在%file下面
vi /usr/lib/rpm/macros,找到%__check_files %{_rpmconfigdir}/check-files %{buildroot} 这一行,把这一行注释掉,然后重新编 译。
- file段重复包含
warning: File listed twice: /etc/pki/CA/cacert.pem warning: File listed twice: /root/cvk_tools-1.1/README.md warning: File listed twice: /root/cvk_tools-1.1/config_ca.sh ...
重复包含了文件
去掉file段重复目录或者文件的包含关系
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?