掌握spec只需读这一篇文章,CentOS、RedHat、SUSE粉的福利来了
发布日期:2021-06-30 21:33:53 浏览次数:2 分类:技术文章

本文共 13342 字,大约阅读时间需要 44 分钟。

什么是 spec(配置规范文件)?RPM 编译过程的核心是处理 .spec 文件。它说明了软件包怎样被配置,补缀哪些补丁,安装哪些文件,被安装到哪里,在安装该包之前或之后需要运行哪些系统级别的活动。它必须手写,但更简单的办法是拿来他人写好的,在此基础上修改。RPM 自身对于你能在 spec 文件中做什么没有太多限制,所以你可以搞的很复杂。

章节预览:

章节内容:

1. spec文件的编码

  如果不需要使用 ASCII字符集以外的字符,那就不用关心 spec 文件的编码。如果使用了 ASCII 字符集以外的字符,请把 spec 文件以 UTF-8 编码保存即可。

2. spec文件的授权

  由于一些法律上的原因,spec 文件必须有一个授权说明的头部。请注意,如果你不写,开放式构建服务就会把它自己默认的加给你。如果这不是你想要的那样子,你可以参考下面的模板写你自己的。——引自openSUSE维基

  当然,如果我们编写非开放式spec文件就不用增加授权说明的头部,模板示例如下:

# # spec file for package python-$FOO # # Copyright (c) $CURRENT_YEAR $YOUR_NAME_WITH_MAIL_ADDRESS # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative.  # Please submit bugfixes or comments via http://bugs.opensuse.org/ #
#中文版 # # # 软件包 软件包名写这里 的 spec 文件 # 版权所有 (c) 年份写这里 你的名字 你的电邮 # # 第三方修订者拥有对本文件的任何修正和增补的版权,除非他们宣布放弃。这份文件本身的授权, # 修复和增补的授权,都和软件包的授权相同(除非软件包不是以开源协议发布,例如MIT协议)。 # 开源协议是一种遵守开源行动制定的开源定义的授权许可。 # 请通过 http://bug.opensuse.org 提交错误报告和评论。 #

3. 编写spec文件

  首先分析一个完整的spec文件:

Name:			rpm包名Version:		版本Release:		发布修正号(在指定版本的第一次发布假设为1,之后每次修改这个版本发布时增加1)Summary:		介绍摘要Group:			包所属组的类型License:		发布许可类型URL:			网址AutoReqProv: 	是否产生RPM依赖关系 yes/noPAckager:		打包者的信息Provides:		指定依赖包或可执行文件Source0: 		源码包说明,多个源码包可以由Source0、Source1等指定Patch0: 		补丁文件说明,与Source0相同,多个补丁文件也可以由Patch0、Patch1等指定PreReq: 		前期依赖BuildRequires: 	编译依赖Requires: 		代码片段的运行依赖%description             					描述标签%prep						 				预备处理%build										编译%install                    				安装%post                     					rpm包安装时执行的内容%postun                						rpm包卸载后执行的内容%files						                指定文件%defattr(-,root,root)       				文件权限%changelog									修订日志

3.1 生成一个空文件的安装包

  接下来在"/root/rpmbuild/SPECS"文件夹内写一个名为test.spec的文件 ,测试打包:

Name:       testVersion:    1.2Release:    1Summary:    测试包License:    GPLURL:        123456Packager:   小明AutoReqProv:no%description%prep%pre%post%preun%postun%files

  这个spec文件只有包的基本描述信息,没有指定具体执行内容,接下来执行这个文件,命令行输入:rpmbuild -ba test.spec,参考图1:

在这里插入图片描述

图1 生成空文件的安装包

  在“/root/rpmbuild/SRPMS/”文件夹内生成了test-1.2-1.src.rpm源包,在"/root/rpmbuild/RPMS"文件夹内生成了test-1.2-1.x86_64.rpm安装包。

3.2 生成一个包含文件的安装包

  我们继续使用test.spec文件,并在“%files”下增加如下内容:

%defattr(-, root, root)/usr/local/test.txt

  完整内容:

Name:       testVersion:    1.2Release:    1Summary:    测试包License:    GPLURL:        123456Packager:   小明AutoReqProv:no%description%prep%pre%post%preun%postun%files%defattr(-, root, root)/usr/local/test.txt

  命令行再次输入:rpmbuild -ba test.spec,参考图2:

![(https://img-blog.csdnimg.cn/20210605215705331.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2EyOTU2MjI2OA==,size_16,color_FFFFFF,t_70)

图2 生成包含文件的安装包

  接下来我们根据错误提示,在“/root/rpmbuild/BUILDROOT”路径下创建test-1.2-1.x86_64文件夹,然后进入test-1.2-1.x86_64文件夹创建“usr/local”路径,之后进入usr/local并创建test.txt文件即可,参考图3:

在这里插入图片描述

图3 创建test.txt文件

  命令行再次输入:rpmbuild -ba test.spec,参考图4:

在这里插入图片描述

图4 再次生成包含文件的安装包

  这次顺利生成test-1.2-1.src.rpm源包和test-1.2-1.x86_64.rpm安装包。

3.3 使用rpm2cpio解压源包和安装包

  接下来我们了解源包和安装包的解压方式,及如何使用源包编译出安装包。

  解压源包:

    首先进入"/root/rpmbuild/SRPMS"文件夹(SRPMS用于存放生成的源包),命令行输入:rpm2cpio test-1.2-1.src.rpm | cpio -div,参考图5:

在这里插入图片描述

图5 解压源包

    我们解压得到test.spec文件,这个文件是我们上述编译出包含文件安装包的spec文件。我们可以通过执行这个spec文件(把test.spec拷贝到“/root/rpmbuild/SPECS”路径下或者在←路径下解压源包)再次生成test-1.2-1.x86_64.rpm安装包。

  解压安装包:

    现在我们进入"/root/rpmbuild/RPMS/x86_64"文件夹(RPMS用于存放生成的安装包,其中x86_64属于我的cpu架构类型),命令行输入:rpm2cpio test-1.2-1.x86_64.rpm | cpio -div,参考图6:

在这里插入图片描述

图6 解压源包

    我们解压得到“usr/local”文件夹和test.txt文件,这与我们在test-1.2-1.x86_64文件夹内创建的内容相同。

    这里需要说明一下,当我们安装test-1.2-1.x86_64.rpm时,包中的文件夹与文件对应这系统中的文件夹与文件,也就是说安装包中的"usr/local/test.txt"将被安装到系统中的"usr/local/test.txt"。

3.4 生成一个完整的源包

  上述示例生成的源包只包含test.spec文件,如果在新系统中尝试编译,需要把test-1.2-1.src.rpm源包和test-1.2-1.x86_64.rpm安装包解压到对应的文件夹内才能编译通过,这在实际项目中不被允许的,并且也比较麻烦,接下来,我们开始来到正规制作源包的道路。

  Source0 在上述介绍中,称为"源码包说明",当然这么说是正确的,但不全面。如我们的test.txt文件不属于源码,也可以通过这种方式生成到源包中。

  首先在test.spec文件中增加如下内容:

    “AutoReqProv:no” 下方:

Source0:    test-1.2.tar.gz由 Name-Version 组成的压缩包名称

    “%install” 下方:

tar xvf %{SOURCE0} --strip-components 1 -C $RPM_BUILD_ROOT这条指令表示解压"SOURCE0"对应的压缩包到"/root/rpmbuild/BUILDROOT"文件夹内

    “/usr/local/test.txt” 下方:

%changelog* Sat Jun  5 2021 小明 
1.2-2- 把/usr/local/test.txt制作到压缩包中,用于生成完整的源包上述为增加更新内容日志,用于描述本次更新做的修改,也方便别人了解这个源包做的变更这次更新属于版本不变,只修改"发布修正号",对Release值加1即可

  完整内容:

Name:       testVersion:    1.2Release:    2Summary:    测试包License:    GPLURL:        123456Packager:   小明AutoReqProv:noSource0:    test-1.2.tar.gz%description%prep%installtar xvf %{SOURCE0} --strip-components 1 -C $RPM_BUILD_ROOT%pre%post%preun%postun%files%defattr(-, root, root)/usr/local/test.txt%changelog* Sat Jun  5 2021 小明 
1.2-2- 把/usr/local/test.txt制作到压缩包中,用于生成完整的源包

  现在test.spec修改完成了,我们到"/root/rpmbuild/SOURCES"文件夹中增加test-1.2.tar.gz压缩包,操作如下,参考图7:

mkdir test-1.2mkdir -p test-1.2/usr/localecho '123456' > test-1.2/usr/local/test.txttar cvf test-1.2.tar.gz test-1.2/

在这里插入图片描述

图7 制作test-1.2.tar.gz压缩包

  接下来我们执行test.spec,命令行输入:rpmbuild -ba test.spec,参考图8、图9:

在这里插入图片描述

图8 生成包含文件的安装包和完整源包(上)

在这里插入图片描述

图9 生成包含文件的安装包和完整源包(下)

  顺利生成test-1.2-2.src.rpm源包和test-1.2-2.x86_64.rpm安装包,解压检查方式参考,我们继续之后的内容,执行源包。

  接下来我们把源包拷贝到SOURCES文件夹内(验证源包是否可以生成安装包与新的源包),解压源包并把test.spec拷贝到"/root/rpmbuild/SPECS"文件夹内,参考图10,命令行输入:

cp /root/rpmbuild/SRPMS/test-1.2-2.src.rpm /root/rpmbuild/SOURCES/rpm2cpio test-1.2-2.src.rpm | cpio -divcp test.spec /root/rpmbuild/SPECS/

在这里插入图片描述

图10 解压源包并放置spec文件

  再次执行test.spec,命令行输入:rpmbuild -ba test.spec,参考图11:

在这里插入图片描述

图11 完整源包解压,生成安装包与新的源包

  经过测试,完整源包可以再次生成安装包与新的源包,并且不需要我们手动在"/root/rpmbuild/BUILDROOT"创建文件夹及拷贝文件。

3.5 rpmbuild内不同文件夹的作用

  在"/root/rpmbuild"文件夹内,我们通过ls指令可以看到好多文件夹,如BUILD、BUILDROOT、RPMS、SOURCES、SPECS、SRPMS,其中:

    BUILD一般在spec执行时,生成完整源码(后续讲述patch时介绍)、编译源码等等,对应spec文件中的"%prep"和"%build"等

    BUILDROOT一般在spec执行时,起到临时安装、测试、打包等等,对应spec文件中的"%install"和"%clean"等

    RPMS用来存放生成的安装包,一般按照cpu架构存放,如"RPMS/x86_64"文件夹内存放x86_64安装包

    SPECS常用来存放spec文件,一般在这个文件夹内编译spec

    SRPMS用来存放源包

3.6 编写一个包含源码的spec文件

  上述的内容属于基础篇,从这部分进入产品spec,首先我们下载<>,并把这个源包中的源码压缩包、patch和spec信息移植到我们的示例中。

  首先在"/root/rpmbuild/SOURCES"文件夹内解压zip-3.0-23.el8.src.rpm,并分析spec文件:

...Source: http://downloads.sourceforge.net/infozip/zip30.tar.gz...Patch1: zip-3.0-exec-shield.patch# Not upstreamed.Patch2: zip-3.0-currdir.patch# Not upstreamed.Patch3: zip-3.0-time.patchPatch4: man.patchPatch5: zip-3.0-format-security.patchPatch6: zipnote.patchPatch7: zip-3.0-configure.patchPatch8: zip-3.0-covscan1.patchBuildRequires: bzip2-develRequires: unzip...%prep%setup -q -n zip30%patch1 -p1 -b .exec-shield%patch2 -p1 -b .currdir%patch3 -p1 -b .time%patch4 -p1 -b .man%patch5 -p1 -b .format-security%patch6 -p1 -b .zipnote%patch7 -p1 -b .zipconfigure%patch8 -p1 -b .covscan1...%buildmake -f unix/Makefile generic_gcc refix=%{_prefix} LFLAGS2="$RPM_LD_FLAGS" CFLAGS_NOOPT="-I. -DUNIX $RPM_OPT_FLAGS" %{?_smp_mflags}%installtar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOTmkdir -p $RPM_BUILD_ROOT%{_bindir}mkdir -p $RPM_BULD_ROOT%{_mandir}/man1make -f unix/Makefile prefix=$RPM_BUILD_ROOT%{_prefix} \        MANDIR=$RPM_BUILD_ROOT%{_mandir}/man1 install...%files%license LICENSE%doc README CHANGES TODO WHATSNEW WHERE README.CR%doc proginfo/algorith.txt%{_bindir}/zipnote%{_bindir}/zipsplit%{_bindir}/zip%{_bindir}/zipcloak%{_mandir}/man1/zip.1*%{_mandir}/man1/zipcloak.1*%{_mandir}/man1/zipnote.1*%{_mandir}/man1/zipsplit.1*

  上述内容需要写入我们的test.spec文件中,并且我们的test.spec文件需要做少量修改:

Source1:    test-1.2.tar.gz...%installtar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOT

  由于zip.spec中定义"SOURCE"表示zip源码压缩包,这里把test.spec中原本的"SOURCE0"修改为"SOURCE1",完整的test.spec如下:

Summary: testName: testVersion: 1.2Release: 3License: GPLSource: http://downloads.sourceforge.net/infozip/zip30.tar.gzSource1:    test-1.2.tar.gzPatch1: zip-3.0-exec-shield.patch# Not upstreamed.Patch2: zip-3.0-currdir.patch# Not upstreamed.Patch3: zip-3.0-time.patchPatch4: man.patchPatch5: zip-3.0-format-security.patchPatch6: zipnote.patchPatch7: zip-3.0-configure.patchPatch8: zip-3.0-covscan1.patchBuildRequires: bzip2-develRequires: unzip%descriptiontest%prep%setup -q -n zip30%patch1 -p1 -b .exec-shield%patch2 -p1 -b .currdir%patch3 -p1 -b .time%patch4 -p1 -b .man%patch5 -p1 -b .format-security%patch6 -p1 -b .zipnote%patch7 -p1 -b .zipconfigure%patch8 -p1 -b .covscan1%buildmake -f unix/Makefile generic_gcc refix=%{_prefix} LFLAGS2="$RPM_LD_FLAGS" CFLAGS_NOOPT="-I. -DUNIX $RPM_OPT_FLAGS" %{?_smp_mflags}%installtar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOTmkdir -p $RPM_BUILD_ROOT%{_bindir}mkdir -p $RPM_BULD_ROOT%{_mandir}/man1make -f unix/Makefile prefix=$RPM_BUILD_ROOT%{_prefix} \        MANDIR=$RPM_BUILD_ROOT%{_mandir}/man1 install%pre%post%preun%postun%files%defattr(-, root, root)/usr/local/test.txt%license LICENSE%doc README CHANGES TODO WHATSNEW WHERE README.CR%doc proginfo/algorith.txt%{_bindir}/zipnote%{_bindir}/zipsplit%{_bindir}/zip%{_bindir}/zipcloak%{_mandir}/man1/zip.1*%{_mandir}/man1/zipcloak.1*%{_mandir}/man1/zipnote.1*%{_mandir}/man1/zipsplit.1*%changelog* Sun Jun  6 2021 小明 
1.2-3- 增加zip源码压缩包及相关信息* Sat Jun 5 2021 小明
1.2-2- 把/usr/local/test.txt制作到压缩包中,用于生成完整的源包

  在新的test.spec中,我们也增加了编译依赖包 bzip2-devel,命令行输入:yum install bzip2-devel,之后再执行spec,命令行输入:rpmbuild -ba test.spec,参考图12:

在这里插入图片描述

图12 spec中增加zip源码编译及安装

  顺利生成test-1.2-3.src.rpm源包和test-1.2-3.x86_64.rpm、test-debugsource-1.2-3.x86_64.rpm、test-debuginfo-1.2-3.x86_64.rpm安装包。

3.7 制作并使用patch

  在移植zip源码压缩包时我们见到了patch文件及在spec中的写法,现在我们先手动制作patch文件,然后讲述patch文件的使用方式。

  命令行输入:rpmbuild -bp test.spec,只生成完整源码(解压源码到"/root/rpmbuild/BUILD"文件夹内并打上patch)。

  现在到"/root/rpmbuild/BUILD"文件夹内可以看到zip30文件夹,拷贝到SOURCES文件夹并再拷贝一份待修改的源码文件夹,参考如下:

cp  -rf /root/rpmbuild/BUILD/zip30/ /root/rpmbuild/SOURCES/cp  -rf /root/rpmbuild/BUILD/zip30/ /root/rpmbuild/SOURCES/zip30.new/

  接下来我们随便修改zip30.new文件中的某个文件,然后生成patch,参考图13:

cd /root/rpmbuild/SOURCES/gedit zip30.new/zip.c增加内容:/* * 增加test示例内容 * 生成patch */

在这里插入图片描述

图13 修改源码文件

  命令行输入:输入diff -Naur zipw30 zip30.new > test_zip_c.patch,然后输入cat test_zip_c.patch,检查生成的patch文件内容,参考图14:

在这里插入图片描述

图14 生成patch文件

  在test.spec文件中我们看到"Patch2: zip-3.0-currdir.patch"、"%patch2 -p1 -b .currdir"等内容,其中"Patch2: zip-3.0-currdir.patch"表示Patch2对应zip-3.0-currdir.patch,"%patch2 -p1 -b .currdir"表示在一级目录打上补丁并生成备份文件,接下来,我们把test_zip_c.patch加入test.spec文件中:

Patch9: test_zip_c.patch...%patch9 -p1

  上述内容中我们增加Patch9表示test_zip_c.patch,并且也在一级目录打上补丁。这里-p1表示一级目录,同样的也有-p0表示根目录、-p2表示二级目录等,如果执行spec时提示某个patch未找到路径,也可以分析patch所在的目录是否正确。

  现在test.spec完整内容为:

Summary: testName: testVersion: 1.2Release: 3License: GPLSource: http://downloads.sourceforge.net/infozip/zip30.tar.gzSource1:    test-1.2.tar.gzPatch1: zip-3.0-exec-shield.patch# Not upstreamed.Patch2: zip-3.0-currdir.patch# Not upstreamed.Patch3: zip-3.0-time.patchPatch4: man.patchPatch5: zip-3.0-format-security.patchPatch6: zipnote.patchPatch7: zip-3.0-configure.patchPatch8: zip-3.0-covscan1.patchPatch9: test_zip_c.patchBuildRequires: bzip2-develRequires: unzip%descriptiontest%prep%setup -q -n zip30%patch1 -p1 -b .exec-shield%patch2 -p1 -b .currdir%patch3 -p1 -b .time%patch4 -p1 -b .man%patch5 -p1 -b .format-security%patch6 -p1 -b .zipnote%patch7 -p1 -b .zipconfigure%patch8 -p1 -b .covscan1%patch9 -p1 %buildmake -f unix/Makefile generic_gcc refix=%{_prefix} LFLAGS2="$RPM_LD_FLAGS" CFLAGS_NOOPT="-I. -DUNIX $RPM_OPT_FLAGS" %{?_smp_mflags}%installtar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOTmkdir -p $RPM_BUILD_ROOT%{_bindir}mkdir -p $RPM_BULD_ROOT%{_mandir}/man1make -f unix/Makefile prefix=$RPM_BUILD_ROOT%{_prefix} \        MANDIR=$RPM_BUILD_ROOT%{_mandir}/man1 install%pre%post%preun%postun%files%defattr(-, root, root)/usr/local/test.txt%license LICENSE%doc README CHANGES TODO WHATSNEW WHERE README.CR%doc proginfo/algorith.txt%{_bindir}/zipnote%{_bindir}/zipsplit%{_bindir}/zip%{_bindir}/zipcloak%{_mandir}/man1/zip.1*%{_mandir}/man1/zipcloak.1*%{_mandir}/man1/zipnote.1*%{_mandir}/man1/zipsplit.1*%changelog* Sun Jun  6 2021 小明 
1.2-3- 增加zip源码压缩包及相关信息* Sat Jun 5 2021 小明
1.2-2- 把/usr/local/test.txt制作到压缩包中,用于生成完整的源包

  命令行输入:rpmbuild -ba test.spec,顺利生成test-1.2-3.src.rpm源包和test-1.2-3.x86_64.rpm、test-debugsource-1.2-3.x86_64.rpm、test-debuginfo-1.2-3.x86_64.rpm安装包。

源码打上patch:

  我们如果想再修改某一处内容,但不想带着刚刚的patch内容,可以通过源码打patch方式,再生成一个新的patch文件。

  进入"/root/rpmbuild/SOURCES"文件夹, 命令行输入:patch -p0 < test_zip_c.patch, 参考图15:

在这里插入图片描述

图15 源码打上patch

  现在我们生成一个新的patch, 命令行输入:diff -Naur zip30 zip30.new > test_zip.patch,然后 cat test_zip.patch内容为空,表示test_zip_c.patch修改的内容已经补丁到zip30文件夹中。

  如果想卸载patch,命令行输入:patch -p0 -R < test_zip_c.patch, 参考图16:

在这里插入图片描述

图16 源码卸载patch

  现在我们再次生成新的patch, 命令行输入:diff -Naur zip30 zip30.new > test_zip.patch,然后 cat test_zip.patch,可以看到上次修改的内容。

4. 常见问题

  执行spec文件时会遇到一些"奇怪"的问题,如源码编译、安装通过,在test或check时报错,这里简单说一下解决方案。

    1)移植suse系统下的源包到centos系列时(包含python文件),遇到python类型不明确,应指定python2 或 python3

      在"%description"之前增加 %{!?install_mod_dir: %global install_mod_dir updates}

    2)Centos系列执行到"%install"时,首先清除"/root/rpmbuild/BUILDROOT"文件夹内的安装包文件夹(比如test-1.2.x86_64),而suse系统未清除

      在"%description"之前增加 %define __spec_install_pre /bin/true ,但这不是较好的办法,可以通过在"%build"末尾处备份安装包文件夹,然后在"%install"中拷贝到"/root/rpmbuild/BUILDROOT"文件夹内

    3)Centos系列源码编译、安装通过,在test或check时报错

      在"%description"之前增加 %global __spec_install_post %{nil}

    4)源码编译、安装通过,在生成debug时报错

      执行spec文件时增加 --nodebuginfo

    5)某些编译依赖包比较难找到怎么办

      执行spec文件时增加 --nodeps,忽略依赖包编译,如果出现报错信息,也许能根据报错信息找到可代替的依赖包

    6)suse系统中的安装包在centos系列安装时找不到依赖包

      分析suse系统中的依赖包内容,并根据依赖包的主要名称搜索(如openssl)在centos下的名称

转载地址:https://lkyof.blog.csdn.net/article/details/117594465 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Linux内核驱动如何编写?我们先从字符驱动入门开始
下一篇:厉害了!VMware ESXi安装记录,附下载

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年04月06日 05时27分41秒