当前位置:   article > 正文

【rpm】源码包制作rpm包|修改rpm、重新制作rpm包_linux rpm封装的时候图标路径怎么修改

linux rpm封装的时候图标路径怎么修改

目录

前言

安装rpmbuild

rpmbuild制作rpm 包

同时生成devel包

阻止rpmbuid打包时strip程序/库

修改rpm、重新制作rpm包

RPM 打包 工具

SPEC文件

 spec文件关键字说明大全

rpmbuild的目录和Spec宏变量和参数说明

preamble部分

Body 部分

标题宏变量/工作目录

符号说明

spec文件不写依赖的情况依然存在依赖库

CMake制作rpm包

HelloWorld

rpm debuginfo包的作用

更多SPEC例子

报错记录

前言

打rpm 包需要的东西有 源码、spec文件(打rpm包的脚本)、rpmbuild工具。

官网教程:RPM Packaging Guide--https://rpm-packaging-guide.github.io/#rpm

推荐文章:

RPM打包原理、示例、详解及备查:https://blog.csdn.net/get_set/article/details/53453320

安装rpmbuild

  1. $yum install rpmbuild
  2. $yum install rpmdevtools
  3. $rpmdev-setuptree

rpmbuild制作rpm 包


1,整理源码
tar -zcvf hello-1.0.tar.gz hello-1.0

hello-1.0 源码打包为.tar.gz压缩包,放到 SOURCE 文件夹下。我门的源码可能是一个tar.gz 的包、也可能是几个文件。
tar.gz源码包的名字格式应该为 helloword-1.0.0.tar.gz (其实就是名字-版本号.tar.gz)

2,编写spec文件
在SPECS文件夹下新建 xxx.spec 打包脚本,其实也就是把我门的源码编译打包成rpm 的一个过程。
(有个rpmdev-newspec工具可以自动生成一个.spec 模板)

  1. vi xxx.spec
  2. Name: hellorpm #名字为源码tar.gz 包的名字
  3. Version: 1.0.0 #版本号,一定要与tar.gz包的一致哦
  4. Release: 1%{?dist} #释出号,也就是第几次制作rpm
  5. Summary: helloword #描述信息/软件包简介,最好不超过50字符
  6. #生成rpm包名:${Name}-${Version}-${Release}.${BuildArch}.rpm
  7. License: GPL #许可,GPL还是BSD等
  8. URL: #自定义该信息,可以写一个网址
  9. Packager: abel
  10. Source0: %{name}-%{version}.tar.gz
  11. #定义用到的source,也就是你的源码
  12. BuildRoot: %_topdir/BUILDROOT
  13. #这个是软件make install 的测试安装目录.
  14. BuildRequires: gcc,make #制作过程中用到的软件包
  15. Requires: python-apscheduler >= 2.1.2-1.el7,python-daemon >= 1.6-1.el7 #软件运行依赖的软件包,也可以指定最低版本如 bash >= 1.1.1
  16. %description #描述,随便写
  17. %prep #打包开始
  18. %setup -q #这个作用静默模式解压并cd
  19. %build #编译制作阶段,主要目的就是编译,如果不用编译就为空
  20. ./configure \
  21. %{?_smp_mflags} #make后面的意思是:如果就多处理器的话make时并行编译
  22. %install #安装阶段//安装之前需初始化安装目录
  23. rm -rf %{buildroot} #先删除原来的安装的,如果你不是第一次安装的话
  24. cp -rp %_topdir/BUILD/%{name}-%{version}/* $RPM_BUILD_ROOT
  25. #将需要需要打包的文件从BUILD 文件夹中拷贝到BUILDROOT文件夹下。
  26. #下面的几步pre、post、preun、postun 没必要可以不写
  27. %pre #rpm安装前制行的脚本
  28. %post #安装后执行的脚本//安装之后需要执行的动作
  29. cp /usr/local/httpd/bin/apachectl /etc/init.d/myhttpd
  30. sed -i '1a # chkconfig: 2345 85 15' /etc/init.d/myhttpd
  31. %preun #卸载前执行的脚本//卸载该rpm包所执行的一些操作
  32. /etc/init.d/myhttpd stop
  33. %postun #卸载后执行的脚本
  34. %clean #清理段,删除buildroot
  35. rm -rf %{buildroot}
  36. %files #rpm要包含的文件//安装之后生成的文件
  37. %defattr (-,root,root,-) #设定默认权限,如果下面没有指定权限,则继承默认
  38. /etc/hello/word/helloword.c #将你需要打包的文件或目录写下来
  39. /usr/local/httpd/bin/*
  40. %dir /usr/local/httpd/logs
  41. %doc /usr/local/httpd/man/*
  42. %doc /usr/local/httpd/manual/*
  43. ### 7.chagelog section //定义一些日志文件,可以使用:rpm -q --changelog httpd查看到
  44. %changelog
  45. * Wed Mar 26 2014 zhangzhg <zsp@tarena.com> 2.2.25
  46. - first rpm from httpd-2.2.25

(这spec里面的%build ,%install 容易写错而报错,所以我们可以不配置 %build ,%install,不让rpmbuild代我们执行build 和install ,我们在外面make install,然后rpmbuild 打包结果)

注意:
以上阶段如果没有操作的话,为空,但是不能有空行,例如build阶段为空应写为
 

  1. %build
  2. %install
  3. xxxxxxxx
  4. 错误示例:
  5. %build
  6. %install
  7. xxxxxxxx

rpm包制作阶段
在这里插入图片描述

3, build rpm包

 spec 文件编写好以后就可以进行打包了。

在SPECS文件夹下执行命令:
rpmbuild -ba hello.spec

如果出错了可以通过 不同的命令来看是在打包的那一步出了问题。

rpmbuild -ba spec_name.spec    <--编译,既生成源码src.rpm又生成二进制rpm 
rpmbuild -bb spec_name.spec    <--编译,只生二进制的rpm 
rpmbuild  
-bs 只生成src的rpm 
-bp 执行到pre 
-bc 执行到 build段 
-bi 执行install段 
-bl 检测有文件没包含 

可以先rpmbuild -bp ,再-bc 再-bi 如果没问题,rpmbuild -ba 生成src包与二进制包。
 

4, 安装
rpmbuild -ivh hello.rpm

5, 查询
rpm -qi hello
 rpm -qa|grep hello

本文参考:
http://laoguang.blog.51cto.com/6013350/1103628/
http://blog.chinaunix.net/uid-23069658-id-3944462.html

原文链接:https://blog.csdn.net/u012373815/article/details/73257754

另外的打包教程:https://blog.csdn.net/weixin_33875564/article/details/92785284
 

同时生成devel包

devel是以子包的形式出现的,所以只需在spec文件里面增加%files devel配置段即可

  1. Name: kmymoney
  2. Summary: The Personal Finances Manager for KDE.
  3. Version: 0.8
  4. Release: 1.%{disttag}%{distver}
  5. #生成rpm包名:${Name}-${Version}-${Release}.${BuildArch}.rpm
  6. License: GPL
  7. Packager: %packer
  8. Group: Productivity/Office/Finance
  9. Source0: %{name}2-%version.tar.bz2
  10. BuildRoot: %{_tmppath}/%{name}2-%{version}-%{release}-build
  11. BuildRequires: kdebase3-devel
  12. Prereq: /sbin/ldconfig
  13. %description
  14. Description goes here...
  15. %package devel
  16. #Requires:
  17. Summary: KMyMoney development files
  18. Group: Productivity/Office/Finance
  19. Provides: kmymoney-devel
  20. %description devel
  21. This package contains necessary header files for KMyMoney development.
  22. ... more to go here ...
  23. %files
  24. ... some files ...
  25. %files devel
  26. ... the devel files ...

示例:

http://kmymoney2.sourceforge.net/phb/rpm-example.html
参考: https://stackoverflow.com/questions/2913130/building-both-devel-and-normal-version-of-a-rpm-package
(摘自:https://phpor.net/blog/post/5673)

阻止rpmbuid打包时strip程序/库

默认情况下,在使用rpmbuild打包时,会对安装的所有文件进行strip操作,去除文件的一些调试信息,并将这些调试信息放到

中,但在很多时候,我们并不需要rpmbuild帮我们执行strip,也不需要生成debuginfo包,所以我们可以修改一下spec文件,关闭这些选项。

针对文件的strip操作是在__os_install_post这个宏中定义的,我们可以运行一下rpmbuild --showrc看一下原始的__os_install_post做了哪些操作:

  1. ...
    -
    14: __os_install_
     
    /usr/lib/rpm/redhat/brp-compress
     
    %{!?__debug_package:/usr/lib/rpm/redhat/brp-stripq %{__strip}}
  2.  /usr/lib/rpm/redhat/brp-strip-static-archive %{__strip}
  3.  /usr/lib/rpm/redhat/brp-strip-comment-note %{__strip} %{__objdump}
  4.  /usr/lib/rpm/brp-python-bytecompile
  5.  /usr/lib/rpm/redhat/brp-python-hardlink
  6.  %{!?__jar_repack:/usr/lib/rpm/redhat/brp-java-repack-jars}
  7. ...

可以看到在打包时会对文件进行一系列操作,比如压缩,strip,编译Python脚本等。

要想不strip,就要把上面带strip的语句去掉,或者让它门失效。

方法1:

在spec文件前面加,直接不做__os_install_post 里的任何事情

%global __os_install_post %{nil}

方法2:

在前面加

%define debug_package %{nil}

%define __strip /bin/true

把__strip 变量定义为/bin/true (原来是/usr/bin/strip),相当于啥也没干。

摘自:https://www.cnblogs.com/LiuYanYGZ/p/9565861.html

$ rpm --showrc | grep -A 4 ': __os_install_post'
-14: __os_install_post  
    /usr/lib/rpm/brp-compress 
    /usr/lib/rpm/brp-strip 
    /usr/lib/rpm/brp-strip-static-archive 
    /usr/lib/rpm/brp-strip-comment-note

Recently, I had an uncommon requirement to disable this option. I do not want to reduce the file size of all files packaged in the rpm. This is achievable using any of 3 mechanisms.

  • Spec file
  • ~/.rpmmacros
  • /etc/rpm/macros

To prevent binary stripping for specific rpm, we could add following line at the top of any rpm spec file.

%global __os_install_post %{nil}

To prevent binary stripping for all rpms created by specific user, we could add following line in ~/.rpmmacros file:

%__os_install_post %{nil}

To prevent binary stripping for all rpms created by all users, we could add following line in /etc/rpm/macros file:

 %__os_install_post %{nil}

修改rpm、重新制作rpm包


提取spec文件
rpmrebuild -s helloworld.spec helloworld.x86_64.rpm

解压原rpm包,得到helloworld
rpm2cpio helloworld.rpm|cpio -div

修改or替换helloworld里面的内容

创建文件夹/tmp/rpmbuild
mkdir /tmp/buildrpm

把helloworld和helloworld.spec 都放入其中<----------------------这一步很关键

cp -r helloworld helloworld.spec /tmp/buildrpm

重新编出rpm包

rpmbuild -ba --buildroot /tmp/buildrpm/ /tmp/buildrpm/helloworld.spec
 

RPM 打包 工具


rpmdevtools包提供的打包RPM的工具。要列出这些工具,请运行:
$ rpm -ql rpmdevtools | grep bin

标题创建打包工作目录
执行
rpmdev-setuptree

$ tree ~/rpmbuild/
/home/user/rpmbuild/
|-- BUILD
|-- RPMS
|-- SOURCES
|-- SPECS
`-- SRPMS

目录名 说明 macros中的宏名
BUILD 编译rpm包的临时目录 %_builddir
BUILDROOT 编译后生成的软件临时安装目录 %_buildrootdir
RPMS 最终生成的可安装rpm包的所在目录 %_rpmdir
SOURCES 所有源代码和补丁文件的存放目录 %_sourcedir
SPECS 存放SPEC文件的目录(重要) %_specdir
SRPMS 软件最终的rpm源码格式存放路径(暂时忽略掉,别挂在心上) %_srcrpmdir

SPEC文件


Spec文件用于告诉rpmbuild如何构建RPM或者SRPM包。(RPM,SRPM区别参见:http://cn.linux.vbird.org/linux_basic/0520rpm_and_srpm.php#intro_whatisrpm)
Spec文件包含preamble和body两部分,preamble部分主要包含一些包的元数据,body部分主要用于打包,安装等

 spec文件关键字说明大全

主要关键字有:

Name: 软件包的名称,后面可使用%{name}的方式引用
Summary: 软件包的内容概要
Version: 软件的实际版本号,例如:1.0.1等,后面可使用%{version}引用
Release: 发布序列号,例如:1%{?dist},标明第几次打包,后面可使用%{release}引用
Group: 软件分组,建议使用:Applications/System
License: 软件授权方式,通常就是GPL
Source: 源代码包,可以带多个用Source1、Source2等源,后面也可以用%{source1}、%{source2}引用
BuildRoot: 这个是安装或编译时使用的“虚拟目录”,考虑到多用户的环境,一般定义为:
%{_tmppath}/%{name}-%{version}-%{release}-root

%{_tmppath}/%{name}-%{version}-%{release}-buildroot-%(%{__id_u} -n}
该参数非常重要,因为在生成rpm的过程中,执行make install时就会把软件安装到上述的路径中,在打包的时候,同样依赖“虚拟目录”为“根目录”进行操作。
后面可使用$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包所依赖的软件包名称,可以用>=或<=表示大于或小于某一特定版本,例如:libpng-devel >= 1.0.20 zlib 注意:“>=”号两边需用空格隔开,而不同软件名称也用空格分开。
还有例如PreReq、Requires(pre)、Requires(post)、Requires(preun)、Requires(postun)、BuildRequires等都是针对不同阶段的依赖指定 

(spec没有写的依赖也依赖进来了?见后面的章节说明)


Provides: 指明本软件一些特定的功能,以便其他rpm识别
Packager: 打包者的信息
%description 软件的详细说明

%define: 预定义的变量,例如定义日志路径: _logpath /var/log/weblog



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

      预处理脚本,这个段是预处理段,通常用来执行一些解开源程序包的命令,为下一步的编译安装作准备。%prep和下面的%build,%install段一样,除了可以执行RPM所定义的宏命令(以%开头)以外,还可以执行SHELL命令,命令可以有很多行,如我们常写的tar解包命令。

%setup

把源码包解压并放好
通常是从/usr/src/asianux/SOURCES里的包解压到/usr/src/asianux/BUILD/%{name}-%{version}中。

%setup -q %{name}-%{version}
一般用%setup -q就可以了,但有两种情况:一就是同时编译多个源码包,二就是源码的tar包的名称与解压出来的目录不一致,此时,就需要使用-n参数指定一下了。

%setup 不加任何选项,仅将软件包打开。

%setup -q 在安静模式下且最少输出

%setup -D #在解压之前禁止删除目录

%setup -a number #在改变目录后,仅解压给定数字的源码,如-a 0 for source0
%setup -n newdir 将软件包解压到newdir目录。
%setup -c 解压缩之前先产生目录。
%setup -b num 包含多个源文件时,将第num个source文件解压缩。
%setup -T 不使用default的解压缩操作。
%setup -T -b 0 将第0个源代码文件SOURCE0解压缩。
%setup -c -n newdir 指定目录名称newdir,并在此目录产生rpm套件。


%patch 打补丁
通常补丁都会一起在源码tar.gz包中,或放到SOURCES目录下。

一般参数为:
%patch -p1 使用前面定义的Patch补丁进行,-p1是忽略patch的第一层目录
%Patch2 -p1 -b xxx.patch 打上指定的补丁,-b是指生成备份文件
◎补充一下 
%patch 最简单的补丁方式,自动指定patch level。 
%patch 0 使用第0个补丁文件,相当于%patch ?p 0。 
%patch -s 不显示打补丁时的信息。 
%patch -T 将所有打补丁时产生的输出文件删除。

%patch #打补丁0

%patch1 #打补丁1

%patch2 #打补丁2

%patch -P 2 #打补丁2

在%build之前,%prep部分将准备好编译工作,解开源码包,并将相应的补丁打进去。


%configure 这个不是关键字,而是rpm定义的标准宏命令。意思是执行源代码的configure配置
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行 ,使用标准写法,会引用/usr/lib/rpm/marcros中定义的参数。
另一种不标准的写法是,可参考源码中的参数自定义,例如:

引用

CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix}

%build 开始构建包

开始编译源码构建包,相当于configure以及make部分

所要执行的命令为生成软件包服务,如

%configure 这个不是关键字,而是rpm定义的标准宏命令。意思是执行源代码的configure配置,可以用rpm –eval '%configure'命令查看该宏
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行操作 ,使用标准写法,会引用/usr/lib/rpm/marcros中定义的参数。
另一种不标准的写法是,可参考源码中的参数自定义,例如:

CFLAGS="$RPM_OPT_FLAGS" CXXFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{_prefix}

make 命令
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make的工作 ,常见写法:

make %{?_smp_mflags} OPTIMIZE="%{optflags}"
都是一些优化参数,定义在/usr/lib/rpm/marcros中


%install 开始把软件安装到虚拟的根目录中

本段是安装段,其中的命令在安装软件包时将执行,如make install命令、cp、mv、install、ln。
在/usr/src/asianux/BUILD/%{name}-%{version}目录中进行make install的操作。这个很重要,因为如果这里的路径不对的话,则下面%file中寻找文件的时候就会失败。 常见内容有:
%makeinstall 这不是关键字,而是rpm定义的标准宏命令,相当于执行make install命令那一步。

也可以使用非标准写法:

make DESTDIR=$RPM_BUILD_ROOT install

make prefix=$RPM_BUILD_ROOT install

make INSTROOT=$RPM_BUILD_ROOT install
需要说明的是,这里的%install主要就是为了后面的%file服务的。所以,还可以使用常规的系统命令:

rm -rf ${RPM_BUILD_ROOT}

mkdir -p $RPM_BUILD_ROOT/{%{_bindir},%{_mandir}/man1,%{_libdir},%{_includedir}}

install -m 755 bzlib.h $RPM_BUILD_ROOT/%{_includedir}

install -m 644 bzip2.1 bzdiff.1 bzgrep.1 bzmore.1  $RPM_BUILD_ROOT/%{_mandir}/man1/

install -d $RPM_BUILD_ROOT/
cp -a * $RPM_BUILD_ROOT/

ln -s file/magic  ${RPM_BUILD_ROOT}%{_datadir}/magic

%find_lang  %{name}

%files -f  %{name}.lang

第一句生成一个名为%{name}.lang的文件,内容是所有的%{name}.mo,第二句意思是一个一个列举.mo文件很麻烦,-f参数是将其后边接的文件合并到%files的文件列表。


%clean 清理临时文件
通常内容为:

[ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
rm -rf $RPM_BUILD_DIR/%{name}-%{version}


※注意区分$RPM_BUILD_ROOT和$RPM_BUILD_DIR:
$RPM_BUILD_ROOT是指开头定义的BuildRoot,而$RPM_BUILD_DIR通常就是指/usr/src/asianux/BUILD,其中,前面的才是%file需要的。 
%pre rpm安装前执行的脚本
%post rpm安装后执行的脚本
%preun rpm卸载前执行的脚本
%postun rpm卸载后执行的脚本

%preun %postun 的区别是什么呢?

前者在升级的时候会执行,后者在升级rpm包的时候不会执行

%files 定义要打包哪些文件或目录到rpm中
这里会在虚拟根目录下进行,千万不要写绝对路径,而应用宏或变量表示相对路径。 如果描述为目录,表示目录中除%exclude外的所有文件。
%defattr (-,root,root) 指定包装文件的属性,分别是(mode,owner,group),-表示默认值,对文本文件是0644,可执行文件是0755

%exclude 列出不想打包到rpm中的文件
※小心,如果%exclude指定的文件不存在,也会出错的。

 
%changelog 变更日志


※特别需要注意的是:%install部分使用的是绝对路径,而%file部分使用则是相对路径,虽然其描述的是同一个地方。千万不要写错。

%file 
就是%file中必须明白,用的是相对目录 引用

分为三类-说明文档(doc),配置文件(config)及执行程序,还可定义文件存取权限,拥有者及组别

ile1 #文件中也可以包含通配符,如*

file2

directory #所有文件都放在directory目录下

%dir /etc/xtoolwait #仅是一个空目录/etc/xtoolwait打进包里

%doc  表示这是文档文件,因此如安装时使用--excludedocs将不安装该文件,

%doc /usr/X11R6/man/man1/xtoolwait.* #安装该文档

%doc README NEWS #安装这些文档到/usr/share/doc/%{name}-%{version} 或者 /usr/doc或者

%docdir #定义说明文档的目录,例如/root,在这一语句后,所有以/root开头的行都被定义为说明文件。

%config /etc/yp.conf #标志该文件是一个配置文件,升级过程中,RPM会有如下动作。

%config(missisgok) /etc/yp.conf 此配置文件可以丢失,即使丢失了,RPM在卸载软件包时也不认为这是一个错误,并不报错。一般用于那些软件包安装后建立的符号链接文件,如

/etc/rc.d/rc5.d/S55named文件,此类文件在软件包卸载后可能需要删除,所以丢失了也不要紧。

%config(noreplace) /etc/yp.conf

#该配置文件不会覆盖已存在文件(RPM包中文件会以.rpmnew存在于系统,卸载时系统中的该配置文件会以.rpmsave保存下来,如果没有这个选项,安装时RPM包中文件会以.rpmorig存在于系统 )

覆盖已存在文件(没被修改),创建新的文件加上扩展后缀.rpmnew(被修改)

%{_bindir}/*

%config  /etc/aa.conf

%ghost /etc/yp.conf #该文件不应该包含在包中,一般是日志文件,其文件属性很重要,但是文件内容不重要,用了这个选项后,仅将其文件属性加入包中。

%attr(mode, user, group) filename #控制文件的权限如%attr(0644,root,root) /etc/yp.conf

如果你不想指定值,可以用-

%config %attr(-,root,root) filename #设定文件类型和权限

%defattr (-,root,root,-)   、%defattr (0644,root,root,0644)   #设置文件的默认权限,-表示默认值,对文本文件是0644,可执行文件是0755

%lang(en) %{_datadir}/locale/en/LC_MESSAGES/tcsh* #用特定的语言标志文件

%verify(owner group size) filename #只测试owner,group,size,默认测试所有

%verify(not owner) filename #不测试owner,测试其他的属性

所有的认证如下:

group:  认证文件的组

maj:    认证文件的主设备号

md5:    认证文件的MD5

min:    认证文件的辅设备号

mode:   认证文件的权限

mtime:  认证文件最后修改时间

owner:  认证文件的所有者

size:   认证文件的大小

symlink:认证符号连接

如果描述为目录,表示目录中出%exclude外的所有文件。

%files 
%defattr(-,root,root) 
%{_bindir} 
%{_libdir} 
%{_datadir} 
%exclude %{_libdir}/debug

由于必须在%file中包括所有套件中的文件,所以,我们需要清楚编译完的套件到底包括那些文件,常见的做法是,人工模拟一次编译的过程:

./configrue --prefix=/usr/local/xxx
make
make DESTDIR=/usr/local/xxx install

make prefix=/usr/local/xxx install
这样,整个套件的内容就会被放到/usr/local/xxx中,可根据情况编写%file和%exclude段
※当然,这个只能对源码按GNU方式编写,并使用GNU autotool创建的包有效,若自定义Makefile则不能一概而论。

%pre: 安装前需要做的任务,如:创建用户
%post: 安装后需要做的任务 如:自动启动的任务
%preun: 卸载前需要做的任务 如:停止任务
%postun: 卸载后需要做的任务 如:删除用户,删除/备份业务数据

%changelog

变更日志,本段是修改日志段。你可以将软件的每次修改记录到这里,保存到发布的软件包中,以便查询之用。每一个修改日志都有这样一种格式:

第一行是:* 星期月日 年 修改人电子信箱。

其中:星期、月份均用英文形式的前3个字母,用中文会报错。接下来的行写的是修改了什么地方,可写多行。一般以减号开始,便于后续的查 阅。

* Mon Mar 31 1997 Erik Troan <ewt@redhat.com>

- Fixed problems caused by 64 bit time_t.


制作补丁 
详细看参考: [原]使用diff同patch工具 
如何编写%file段 
由于必须在%file中包括所有套件中的文件,所以,我们需要清楚编译完的套件到底包括那些文件?
常见的做法是,人工模拟一次编译的过程: 这样,整个套件的内容就会被放到/usr/local/xxx中,可根据情况编写%file和%exclude段。※当然,这个只能对源码按GNU方式编写,并使用GNU autotool创建的包有效,若自定义Makefile则不能一概而论。 
关于rpm中的执行脚本 
如果正在制作的rpm包是准备作为放到系统安装光盘中的话,则需要考虑rpm中定义的脚本是否有问题。由于系统在安装的时候只是依赖于一个小环境进行,而该环境与实际安装完的环境有很大的区别,所以,大部分的脚本在该安装环境中都是无法生效,甚至会带来麻烦的。
所以,对于这样的,需要放到安装光盘中的套件,不加入执行脚本是较佳的方法。
另外,为提供操作中可参考的信息,rpm还提供了一种信号机制:不同的操作会返回不同的信息,并放到默认变量$1中。

更多:rpm打包,rpmbuild SPEC文件深度说明_https://blog.csdn.net/u013425438/article/details/80417542

详细介绍在:https://www.cnblogs.com/ilanni/p/4312581.html

https://blog.51cto.com/luweiv998/2354385
https://blog.csdn.net/csdn_763871244/article/details/99937600

rpmbuild的目录和Spec宏变量和参数说明

preamble部分

SPEC 指令

说明

Name

The base name of the package, which should match the SPEC file name.

包的基本名称,应与SPEC文件名匹配。

Version

软件的上游版本号。

Release

The number of times this version of the software was released. Normally, set the initial value to 1%{?dist}, and increment it with each new release of the package. Reset to 1 when a new Version of the software is built.

此版本软件的发布次数。通常,将初始值设置为1%{?dist},并该版本的每次新发布递增。生成新版本的软件时,重置为1。

Summary

一个简短的、单行的包摘要。

License

The license of the software being packaged. For packages distributed in community distributions such as Fedora this must be an open source license abiding by the specific distribution’s licensing guidelines.


正在打包的软件的许可证。对于在社区发行版(如Fedora)中分发的包,这必须是一个开源许可证,遵守特定发行版的许可准则。

URL

The full URL for more information about the program. Most often this is the upstream project website for the software being packaged.

有关该程序的详细信息的完整URL。通常,这是打包软件的上游项目网站。

Source0

Path or URL to the compressed archive of the upstream source code (unpatched, patches are handled elsewhere). This should point to an accessible and reliable storage of the archive, for example, the upstream page and not the packager’s local storage. If needed, more SourceX directives can be added, incrementing the number each time, for example: Source1, Source2, Source3, and so on.

上游源代码压缩包的路径或URL(未修补,补丁在其他地方处理)。这应该指向可访问且可靠的包路径,例如,上游页面,而不是打包程序的本地存储。如果需要,可以添加更多的SourceX地址,每次递增数字,例如:Source1、Source2、Source3等。

Patch0

The name of the first patch to apply to the source code if necessary. If needed, more PatchX directives can be added, incrementing the number each time, for example: Patch1, Patch2, Patch3, and so on.

必要时应用于源代码的第一个补丁的名称。如果需要,可以添加更多的PatchX,每次递增数字,例如:Patch1、Patch2、Patch3等。

BuildArch

If the package is not architecture dependent, for example, if written entirely in an interpreted programming language, set this to BuildArch: noarch. If not set, the package automatically inherits the Architecture of the machine on which it is built, for example x86_64.

如果包不依赖于平台架构,例如和硬件平台无关的脚本,请将其设置为BuildArch:noarch。如果未设置,软件包将自动设置为 机器的平台结构,例如x86_64。

BuildRequires

A comma- or whitespace-separated list of packages required for building the program written in a compiled language. There can be multiple entries of BuildRequires, each on its own line in the SPEC file.

编译程序用到的文件的列表,用逗号或空格分隔。在SPEC文件中,可以有多个BuildRequires条目,,每个条目单独一行

Requires

A comma- or whitespace-separated list of packages required by the software to run once installed. There can be multiple entries of Requires, each on its own line in the SPEC file.

软件安装后运行所依赖的rpm的文件列表,用逗号或空格分隔。在SPEC文件中,可以有多个Requires条目,每个条目单独一行

(spec没有写的依赖也依赖进来了?见后面的章节说明)

ExcludeArch

If a piece of software can not operate on a specific processor architecture, you can exclude that architecture here.

如果某个软件不能在特定的处理器架构上运行,则可以在此处排除该架构。

例如:要生成的包名是 python-2.7.5-34.el7.x86_64,则

Name:python,

Version:2.7.5,

Release:34.el7

最后一个标记是x86_64,表示体系结构。体系结构标记不受RPM打包器的直接控制,而是由rpmbuild构建环境定义。唯一的例外是要构建的RPM与硬件平台无关时,自己可以填写BuildArch:noarch.

Body 部分

SPEC 指令

说明

%description

A full description of the software packaged in the RPM. This description can span multiple lines and can be broken into paragraphs.

RPM中软件包的完整描述。此描述可以跨越多行,并可以拆分为段落。

%prep

Command or series of commands to prepare the software to be built, for example, unpacking the archive in Source0. This directive can contain a shell script.

构建之前的处理,例如,创建or删除目录,解压从Source0获取到的压缩包……可以包含shell脚本。

%build

Command or series of commands for actually building the software into machine code (for compiled languages) or byte code (for some interpreted languages).

编译生成程序的的命令或一系列命令。

%install

Command or series of commands for copying the desired build artifacts from the %builddir (where the build happens) to the %buildroot directory (which contains the directory structure with the files to be packaged). This usually means copying files from ~/rpmbuild/BUILD to ~/rpmbuild/BUILDROOT and creating the necessary directories in ~/rpmbuild/BUILDROOT. This is only run when creating a package, not when the end-user installs the package. See Working with SPEC files for details.


用于将所需的生成工件从%builddir(生成发生的位置)复制到%buildroot目录(包含要打包的文件的目录结构)的命令或一系列命令。这通常意味着将文件从~/rpmbuild/BILD复制到~/rpmuild/BILDROOT,并在~/rmbuild/BILDLOOT中创建必要的目录。这仅在创建包时运行,而不是在最终用户安装包时运行。有关详细信息,请参见使用SPEC文件:https://rpm-packaging-guide.github.io/#working-with-spec-files

%check

Command or series of commands to test the software. This normally includes things such as unit tests.

测试软件的命令或一系列命令。这通常包括单元测试等内容。

%files

The list of files that will be installed in the end user’s system.

将安装在最终用户系统中的文件列表。(也就是需要打包进rpm包的文件列表--绝对路径)

%changelog

A record of changes that have happened to the package between different Version or Release builds.

不同版本或发行版本之间对包所做更改的记录。

标题宏变量/工作目录


默认工作路径的确定,通常由在/usr/lib/rpm/macros这个文件里的一个叫做%_topdir的宏变量来定义。

在%_topdir目录下一般需要建立6个目录:
$_topdir /root/rpmbuild

目录名 说明 macros中的宏名
BUILD 编译rpm包的临时目录 %_builddir
BUILDROOT 编译后生成的软件临时安装目录 %_buildrootdir
RPMS 最终生成的可安装rpm包的所在目录 %_rpmdir
SOURCES 所有源代码和补丁文件的存放目录 %_sourcedir
SPECS 存放SPEC文件的目录(重要) %_specdir
SRPMS 软件最终的rpm源码格式存放路径(暂时忽略掉,别挂在心上) %_srcrpmdir

Spec文件的宏定义:
rpmbuild --showrc | grep topdir #工作车间目录:_topdir /root/rpmbuild
-14: _builddir %{_topdir}/BUILD
-14: _buildrootdir %{_topdir}/BUILDROOT
-14: _rpmdir %{_topdir}/RPMS
-14: _sourcedir %{_topdir}/SOURCES
-14: _specdir %{_topdir}/SPECS
-14: _srcrpmdir %{_topdir}/SRPMS
-14: _topdir /root/rpmbuild

rpmbuild --showrc显示所有的宏,以下划线开头:

一个下划线:定义环境的使用情况,
二个下划线:通常定义的是命令,
为什么要定义宏,因为不同的系统,命令的存放位置可能不同,所以通过宏的定义找到命令的真正存放位置

符号说明


什么是 1%{?dist} : 如果%{dist}未定义返回1,否则返回1%{dist},

if 0%{?flag}; then
foo
fi

如果%{flag}被定义了,条件语句为:0%{flag},执行if block; 反之,条件语句为:0, 不执行if block。
注意:%{?flag}前必须加0,否则如果%{?flag}未定义,if语句停止执行并退出。
%{?flag: …}:如果%{flag}被定义,则展开"…"部分

作者:weiee
链接:https://www.jianshu.com/p/f1e36e4a152c
 

Note:

rpm --eval %{kernel_module_package_buildreqs}->kernel-devel
rpm --eval %{kernel_module_package} 会输出一些关于制作linux驱动的一些代码和一些依赖
重要的是包含了%files 路径,%files包含了需要打包进入rpm包里的文件,如果是 / 开头那么其实是BUILDROOT路径
制作的时候%install 是安装到~/rpmbuild/BUILDROOT的,最后发布rpm后运行yum install rpm会
把驱动安装到lib/modules/( u n a m e − r ) / u p d a t e s B u i l d R o o t : 在 e x p o r t I N S T A L L M O D P A T H = (uname -r)/updates BuildRoot: 在 %install 阶段(%build 阶段后)文件需要安装至此位置。Fedora 不需要此标签,只有 EPEL5 还需要它。默认情况下,根目录为 “%{_topdir}/BUILDROOT/”。 %_buildrootdir 最终安装目录 ~/rpmbuild/BUILDROOT 保存 %install 阶段安装的文件 export INSTALL_MOD_PATH=(uname−r)/updatesBuildRoot:在exportINSTALL 
MOD PATH=RPM_BUILD_ROOT export INSTALL_MOD_DIR=updates 这两句话说明了安装的时候的路径,是~/rpmbuild/BUILDROOT ,最后里面会生成对应的lib/modules/$(uname -r)/updates 下面

在这里插入图片描述

如果%clean 不加会默认把BUILDROOT给删掉

原文链接:https://blog.csdn.net/Wang20122013/article/details/122498396

spec文件不写依赖的情况依然存在依赖库

由于很多东西需要保密,所以不放截图
rpm -qlp *.rpm查看rpm包中携带的文件
ldd file检测编译文件夹下的bin文件是否是bin文件带来的依赖
vi /usr/lib/rpm/micro编辑rpm的编译宏
找到455,456行,注释掉

  1. 455 #%__find_provides %{_rpmconfigdir}/find-provides
  2. 456 #%__find_requires %{_rpmconfigdir}/find-requires

重新编译,使用rpm -qpR *.rpm检测新生成的rpm是否带有依赖
如果问题未被解决,则在spec文件Requires下面加入一行AutoReqprv: no来规避掉二进制文件带来的依赖 AUTOREQ=0  (注意使用AutoReqprv:no 之后需要手工写spc 该rpm包的provider


链接:https://www.jianshu.com/p/3eff04b20f93

The AUTOREQPROV, AUTOREQ, and AUTOPROV tags are not available for use with --queryformat.

Available Tags For --queryformat---http://ftp.rpm.org/max-rpm/ch-queryformat-tags.html

rpm包是怎么自动搞进一些依赖项的:

答案是rpmbuild使用ldd命令对%files部分中包含的任何二进制文件生成自动依赖关系:

Automatic Dependencies


 

CMake制作rpm包


(摘自:https://blog.csdn.net/qq_29493353/article/details/90205415)

也可以使用cmake 制作rpm包,CMake中包含的三个工具(cmake cpack ctest)中的cpack工具。他可以帮助快速的打包发布你的程序。

HelloWorld


目录结构

在这里插入图片描述

CMakeList.txt

  1. cmake_minimum_required(VERSION 2.8)
  2. # 设置项目名称
  3. project(HelloWorld)
  4. # 设置安装路径, 默认/usr/local。也可以是idc经常安装的/data/home/user00/xxxserver等
  5. # set(CPACK_PACKAGING_INSTALL_PREFIX /opt)
  6. # 如果不是CMake构建的,设置CMAKE_CURRENT_BINARY_DIR为Makefile的构建目录
  7. set(CMAKE_CURRENT_BINARY_DIR ..)
  8. # 批量的安装指令,目录、程序、库文件、头文件等
  9. install(PROGRAMS bin/hello DESTINATION bin)
  10. install(FILES bin/hello.a DESTINATION lib)
  11. install(FILES src/hello.h DESTINATION include)
  12. # 以下为RPM信息的设置,包名,概述,供应者,版本, 分组等等信息,通过其变量名称可以知道意思
  13. set(CPACK_PACKAGE_NAME "wetest-helloworld")
  14. set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Simple CPack HelloWorld")
  15. set(CPACK_PACKAGE_VENDOR "WeTest")
  16. set(CPACK_PACKAGE_VERSION "1.0.0")
  17. set(CPACK_PACKAGE_VERSION_MAJOR "1")
  18. set(CPACK_PACKAGE_VERSION_MINOR "0")
  19. set(CPACK_PACKAGE_VERSION_PATCH "0")
  20. set(CPACK_RPM_PACKAGE_GROUP "WeTest")
  21. set(CPACK_RPM_PACKAGE_URL "http://wetest.qq.com")
  22. set(CPACK_RPM_PACKAGE_DESCRIPTION "WeTest Server Dependencies")
  23. set(CPACK_PACKAGE_RELEASE 1)
  24. set(CPACK_RPM_PACKAGE_LICENSE "WeTest Licence")
  25. # 设置默认生成器,RPM生成器会构建RPM安装包,其它还有TGZ/ZIP等
  26. set(CPACK_GENERATOR "RPM")
  27. # 安装前和安装后执行的shell脚本, 会打包到RPM中,安装时执行。这里可扩展性很强, 放在源码目录下即可
  28. # set(CPACK_RPM_PRE_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/pre_script.sh)
  29. # set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/post_script.sh)
  30. # 引入CPack模块,必须的
  31. include(CPack)

构建

mkdir build && cd build
$ cmake …
$ make install
$ cpack

其中capck支持其他的打包格式,比如tar.gz和zip,只需要执行cpack -G TGZ 或者 cpack -G ZIP就可打包成相应的格式。

结论
以上主要是用cpack打包开发程序,其实可以针对很多东西制作rpm包,比如很多依赖已经用源码安装好的开发坏境,也可以打包,公司tlinux的提供了兼容性。比如mysql++已经装在系统/usr/local/当中,替换模板中的描述和install指令如下即可:

file(GLOB mysqlppso /usr/local/lib/libmysqlpp*)
install(DIRECTORY /usr/local/include/mysql++ DESTINATION include)
install(PROGRAMS ${mysqlppso} DESTINATION lib)
希望能够帮助大家快速部署,也推荐使用CMake来完成构建任务,如果有用的话之后介绍下ctest + boost unit test做单元测试。
 

rpm debuginfo包的作用

一般在linux上,编写一个软件后,都会用rpmbuild工具打包成rpm包,然后发给别人去部署。
rpm包里一般就是有一些可执行文件,静态库或者动态库,但是不包含源代码。
那么有时候为了调试方便,还会同时生成相应的rpm debuginfo包,这样就可以方便调试。只要客户安装了普通rpm包和相应版本的debuginfo包,就可以gdb调试了
更多详细请看原文《rpm debuginfo包的作用》:https://blog.csdn.net/chenj_freedom/article/details/84023885

更多SPEC例子

#前期准备:       yum -y install rpmdevtools pcre-devel   
#-------------------------------------------------------
# 查看默认宏:   rpmbuild --showrc  |  grep  "_topdir"
#  _builddir      %{_topdir}/BUILD
#  _buildrootdir %{_topdir}/BUILDROOT
#  _rpmdir       %{_topdir}/RPMS
#  _sourcedir    %{_topdir}/SOURCES    --->  原材料,如源码包,文档所在目录,需事先将打包的源文件或脚本存放在此目录内......
#  _specdir      %{_topdir}/SPECS   --->  管理rpm制作过程的描述文件所在的目录
#  _srcrpmdir    %{_topdir}/SRPMS
#  _topdir        %{getenv:HOME}/rpmbuild   --->  rpmbuild目录的顶层入口
#-------------------------------------------------------
#生成~/rpmbuild及子目录:    rpmdev-setuptree
#生成rpmbuild的spec模板:    rpmdev-newspec -o Name-version.spec  --->   生成的SPEC文件主要用于描述RPM包的制作和生成过程
#eg:
#[root@localhost ~]#  rpmdev-setuptree && cd rpmbuild ; tree
#.
#├── BUILD
#├── RPMS
#├── SOURCES
#├── SPECS
#└── SRPMS
#------------------------------------------------------------------------------------------------------------------------- 以下是spec文件内容:
 
#自定义宏,相当于Linux中"Key-Value"变量形式
%define Name nginx  #--->  名称
%define Version 1.2.2  #--->  版本
%define CONFIGFILE 1.conf   #--->   本rpm包中需更换的配置文件......
%define InstallPath /usr/local/nginx  #--->   本rpm包默认安装的路径
 
#定义软件包信息,即:"rpm -qi name.rpm " 查看到的内容
Name:           %{Name}   #--->   引用宏
Version:        %{Version}   #--->   引用宏
Release:        1%{?dist}   #--->   引用宏(自带宏)
Summary:        ....................................... #--->  一些描述信息
#生成rpm包名:${Name}-${Version}-${Release}.${BuildArch}.rpm
License:        GPLv2  #--->  授权协议
URL:            inmoonlight@.163.com
buildroot:      %{_topdir}/BUILDROOT   #--->  指定生产车间(非常重要,因在生成rpm过程中执行make install时会把软件安装到此路径,打包时同样依此目录为“根目录”进行操作)
Source0:        %{Name}-%{Version}.tar.gz   #---> 指定源码编译的文件,默认路径:%{_topdir}/SOURCES  
SOURCE1:        %{CONFIGFILE}  #---> 指定要替换的配置文件,默认路径:%{_topdir}/SOURCES  
BuildRequires:      gcc,make,automake,binutils  #--->  软件依赖信息
Requires:      bash >= 2.0 #--->  定义软件依赖信息,该rpm包所依赖的软件包名称,可用>=或<=表示大或小于特定版本
%description
This is %{Name} .....Just a test rpm suite.............
 
#安装前的准备工作,此处可写入执行脚本
%pre
useradd %{Name} -s /sbin/nologin
 
#安装前的准备:此段默认将Source目录内的源码包在BUILD目录解压为%{Name}-%{Version}格式的目录
%prep
%setup -q -n %{Name}-%{Version}  #---> 参数:-c 解压缩之前先产生目录,-n newdir 将软件包解压在newdir目录
 
#定义config动作
%build
./configure --prefix=%{InstallPath} --user=%{Name} --group=%{Name} 
make %{?_smp_mflags}
 
#定义执行make install时的动作
%install
rm -rf %{buildroot} #---> 删除生产车间内的残留文件
%{__make} install DESTDIR=%{buildroot} #---> 将软件安装至指定的目录
%{__install} -p -D -m 0755  %{SOURCE1} %{buildroot}/usr/local/nginx/conf/%{CONFIGFILE} #--->  替换指定的配置文件
 
#赋予文件的默认权限及设置需在RPM包中保留的文件
%files
%doc
%defattr(-,root,root,-)  #---> 指定包装文件属性,分别是(mode,owner,group),- 表示默认值,文本文件是0644,可执行文件0755
%attr(0755,root,root) /usr/local/nginx/sbin/nginx  #--->  针对单一文件设置权限
%{_prefix}/*
%{_prefix}/local/nginx/conf/%{CONFIGFILE}
 
#制作完成后的清理工作
%clean
rm -rf %{buildroot}
 
#安装后的执行工作,此处可写入执行脚本
%post
chkconfig --add nginx
chkconfig --level 345 nginx on
 
#变更日志
%changelog
 
#---------------------------------------------------------------------------------------------
#    2.1 介绍区域的SOURCE0下增加如下
#    Source0:        %{name}-%{version}.tar.gz 
#    Source1:        index.html 
#    Source2:        init.nginx 
#    Source3:        fastcgi_params 
#    Source4:        nginx.conf 
 
#    2.2 安装区域增加如下
#    make install DESTDIR=%{buildroot} 
#    %{__install} -p -D %{SOURCE1} %{buildroot}/usr/html/index.html  #%{__install}这个宏代表install命令
#    %{__install} -p -D -m 0755 %{SOURCE2} %{buildroot}/etc/rc.d/init.d/nginx 
#    %{__install} -p -D %{SOURCE3} %{buildroot}/etc/nginx/fastcgi_params 
#    %{__install} -p -D %{SOURCE4} %{buildroot}/etc/nginx/nginx.conf 
 
 
将脚本制作成为RPM包的例子:
 
Name: eee
Version: 1
Release: 1%{?dist}
Summary:1111
 
License:GPLv2
URL:    inmoonlighy.11.cn
Source0: eee
 
%description
.....
 
%install
rm -rf %{buildroot}
mkdir -p %{buildroot}/bin/
cp -rf  %{SOURCE0} %{buildroot}/bin
 
%files
/bin/eee
 
%changelog
 
#注:安装时失败应加“rpm -ivh --force ***.rpm 进行尝试”
#---------------------------------------------------------------------------------------------
#rpmbuild:
#    -bl          检查spec中的%file段来查看文件是否齐全
#    -ba         建立二进制包&源码
#    -bb         建立二进制包
#    -bp        执行到 prep 阶段
#    -bc         执行到 build 阶段
#    -bi         执行到 install 阶段

#制作:    cd /usr/src/redhat/SPECS/ ; rpmbuild -ba nginx.spec   --> 生成:/usr/src/redhat/RPMS/i386/nginx-1.2.1-1.el5.ngx.i386.rpm
#测试:    rpm -ivh /usr/src/redhat/RPMS/i386/nginx-1.2.1-1.el5.ngx.i386.rpm
 

《使用cpack打包源码并编写自动化脚本上传到仓库》
https://blog.csdn.net/weixin_34319640/article/details/87972767

报错记录


make: *** No rule to make target `install’


(摘自:https://www.cnblogs.com/chenyaling/p/5806965.html)

遇到最大的坑就是%install部分的make install

网上的资料是这样说的:

本段是安装段,其中的命令在安装软件包时将执行,如make install命令。
%makeinstall 这不是关键字,而是rpm定义的标准宏命令。也可以使用非标准写法:引用make DESTDIR=R P M B U I L D R O O T i n s t a l l 或引用 m a k e p r e f i x = RPM_BUILD_ROOT install或引用make prefix=RPM BUILD ROOTinstall或引用makeprefix=RPM_BUILD_ROOT install
需要说明的是,这里的%install主要就是为了后面的%file服务的。所以,还可以使用常规的系统命令:
引用install -d $RPM_BUILD_ROOT/
cp -a * $RPM_BUILD_ROOT/
但是我每次使用make install时候都会报错make: *** No rule to make target ‘install’。换成install -d的写好就可以,我也不明白是为什么。

后来发现,使用make install是在已经编写过Makefile的前提下进行的,报错中的install其实是Makefile中的写好的target。

举个例子,在Makefile中编写,如下:

install-oem:
mkdir -p $(LIBDIR)/xsconsole/plugins-oem
则在%install中就可以这样写:

%install
make install-oem DESTDIR=$RPM_BUILD_ROOT
否则,当然会报错找不到target。

朱老师说现在使用Makefile已经有点过时了。我是觉得Makefile很烦,写错了,还要重新打包,生成压缩文件才行。改多了之后根本受不了,不如直接在%install里面直接写内容,这样改起来也方便。
 

安装 rpm包出现error: unpacking of archive failed on file

https://blog.csdn.net/qq_36911595/article/details/112668637

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/345611
推荐阅读
相关标签
  

闽ICP备14008679号