赞
踩
什么是 spec(配置规范文件)?RPM 编译过程的核心是处理 .spec 文件。它说明了软件包怎样被配置,补缀哪些补丁,安装哪些文件,被安装到哪里,在安装该包之前或之后需要运行哪些系统级别的活动。它必须手写,但更简单的办法是拿来他人写好的,在此基础上修改。RPM 自身对于你能在 spec 文件中做什么没有太多限制,所以你可以搞的很复杂。
1. spec文件的编码
2. spec文件的授权
3. 编写spec文件
3.1 生成一个空文件的安装包
3.2 生成一个包含文件的安装包
3.3 使用rpm2cpio解压源包和安装包
3.4 生成一个完整的源包
3.5 rpmbuild内不同文件夹的作用
3.6 编写一个包含源码的spec文件
3.7 制作并使用patch
4. 常见问题
如果不需要使用 ASCII字符集以外的字符,那就不用关心 spec 文件的编码。如果使用了 ASCII 字符集以外的字符,请把 spec 文件以 UTF-8 编码保存即可。
由于一些法律上的原因,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 提交错误报告和评论。
#
首先分析一个完整的spec文件:
Name: rpm包名 Version: 版本 Release: 发布修正号(在指定版本的第一次发布假设为1,之后每次修改这个版本发布时增加1) Summary: 介绍摘要 Group: 包所属组的类型 License: 发布许可类型 URL: 网址 AutoReqProv: 是否产生RPM依赖关系 yes/no PAckager: 打包者的信息 Provides: 指定依赖包或可执行文件 Source0: 源码包说明,多个源码包可以由Source0、Source1等指定 Patch0: 补丁文件说明,与Source0相同,多个补丁文件也可以由Patch0、Patch1等指定 PreReq: 前期依赖 BuildRequires: 编译依赖 Requires: 代码片段的运行依赖 %description 描述标签 %prep 预备处理 %build 编译 %install 安装 %post rpm包安装时执行的内容 %postun rpm包卸载后执行的内容 %files 指定文件 %defattr(-,root,root) 文件权限 %changelog 修订日志
接下来在"/root/rpmbuild/SPECS"文件夹内写一个名为test.spec的文件 ,测试打包:
Name: test Version: 1.2 Release: 1 Summary: 测试包 License: GPL URL: 123456 Packager: 小明 AutoReqProv:no %description %prep %pre %post %preun %postun %files
这个spec文件只有包的基本描述信息,没有指定具体执行内容,接下来执行这个文件,命令行输入:rpmbuild -ba test.spec,参考图1:
在“/root/rpmbuild/SRPMS/”文件夹内生成了test-1.2-1.src.rpm源包,在"/root/rpmbuild/RPMS"文件夹内生成了test-1.2-1.x86_64.rpm安装包。
我们继续使用test.spec文件,并在“%files”下增加如下内容:
%defattr(-, root, root)
/usr/local/test.txt
完整内容:
Name: test Version: 1.2 Release: 1 Summary: 测试包 License: GPL URL: 123456 Packager: 小明 AutoReqProv:no %description %prep %pre %post %preun %postun %files %defattr(-, root, root) /usr/local/test.txt
命令行再次输入:rpmbuild -ba test.spec,参考图2:
接下来我们根据错误提示,在“/root/rpmbuild/BUILDROOT”路径下创建test-1.2-1.x86_64文件夹,然后进入test-1.2-1.x86_64文件夹创建“usr/local”路径,之后进入usr/local并创建test.txt文件即可,参考图3:
命令行再次输入:rpmbuild -ba test.spec,参考图4:
这次顺利生成test-1.2-1.src.rpm源包和test-1.2-1.x86_64.rpm安装包。
接下来我们了解源包和安装包的解压方式,及如何使用源包编译出安装包。
解压源包:
首先进入"/root/rpmbuild/SRPMS"文件夹(SRPMS用于存放生成的源包),命令行输入:rpm2cpio test-1.2-1.src.rpm | cpio -div,参考图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:
我们解压得到“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"。
上述示例生成的源包只包含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 小明 <xiaoming@test.com> 1.2-2
- 把/usr/local/test.txt制作到压缩包中,用于生成完整的源包
上述为增加更新内容日志,用于描述本次更新做的修改,也方便别人了解这个源包做的变更
这次更新属于版本不变,只修改"发布修正号",对Release值加1即可
完整内容:
Name: test Version: 1.2 Release: 2 Summary: 测试包 License: GPL URL: 123456 Packager: 小明 AutoReqProv:no Source0: test-1.2.tar.gz %description %prep %install tar 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 小明 <xiaoming@test.com> 1.2-2 - 把/usr/local/test.txt制作到压缩包中,用于生成完整的源包
现在test.spec修改完成了,我们到"/root/rpmbuild/SOURCES"文件夹中增加test-1.2.tar.gz压缩包,操作如下,参考图7:
mkdir test-1.2
mkdir -p test-1.2/usr/local
echo '123456' > test-1.2/usr/local/test.txt
tar cvf test-1.2.tar.gz test-1.2/
接下来我们执行test.spec,命令行输入:rpmbuild -ba test.spec,参考图8、图9:
顺利生成test-1.2-2.src.rpm源包和test-1.2-2.x86_64.rpm安装包,解压检查方式参考3.3 使用rpm2cpio解压源包和安装包,我们继续之后的内容,执行源包。
接下来我们把源包拷贝到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 -div
cp test.spec /root/rpmbuild/SPECS/
再次执行test.spec,命令行输入:rpmbuild -ba test.spec,参考图11:
经过测试,完整源包可以再次生成安装包与新的源包,并且不需要我们手动在"/root/rpmbuild/BUILDROOT"创建文件夹及拷贝文件。
在"/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用来存放源包
上述的内容属于基础篇,从这部分进入产品spec,首先我们下载<zip-3.0-23.el8.src.rpm>,并把这个源包中的源码压缩包、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.patch Patch4: man.patch Patch5: zip-3.0-format-security.patch Patch6: zipnote.patch Patch7: zip-3.0-configure.patch Patch8: zip-3.0-covscan1.patch BuildRequires: bzip2-devel Requires: 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 ... %build make -f unix/Makefile generic_gcc refix=%{_prefix} LFLAGS2="$RPM_LD_FLAGS" CFLAGS_NOOPT="-I. -DUNIX $RPM_OPT_FLAGS" %{?_smp_mflags} %install tar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_bindir} mkdir -p $RPM_BULD_ROOT%{_mandir}/man1 make -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
...
%install
tar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOT
由于zip.spec中定义"SOURCE"表示zip源码压缩包,这里把test.spec中原本的"SOURCE0"修改为"SOURCE1",完整的test.spec如下:
Summary: test Name: test Version: 1.2 Release: 3 License: GPL Source: http://downloads.sourceforge.net/infozip/zip30.tar.gz Source1: test-1.2.tar.gz Patch1: zip-3.0-exec-shield.patch # Not upstreamed. Patch2: zip-3.0-currdir.patch # Not upstreamed. Patch3: zip-3.0-time.patch Patch4: man.patch Patch5: zip-3.0-format-security.patch Patch6: zipnote.patch Patch7: zip-3.0-configure.patch Patch8: zip-3.0-covscan1.patch BuildRequires: bzip2-devel Requires: unzip %description test %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 %build make -f unix/Makefile generic_gcc refix=%{_prefix} LFLAGS2="$RPM_LD_FLAGS" CFLAGS_NOOPT="-I. -DUNIX $RPM_OPT_FLAGS" %{?_smp_mflags} %install tar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_bindir} mkdir -p $RPM_BULD_ROOT%{_mandir}/man1 make -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 小明 <xiaoming@test.com> 1.2-3 - 增加zip源码压缩包及相关信息 * Sat Jun 5 2021 小明 <xiaoming@test.com> 1.2-2 - 把/usr/local/test.txt制作到压缩包中,用于生成完整的源包
在新的test.spec中,我们也增加了编译依赖包 bzip2-devel,命令行输入:yum install bzip2-devel,之后再执行spec,命令行输入:rpmbuild -ba test.spec,参考图12:
顺利生成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安装包。
在移植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
*/
命令行输入:输入diff -Naur zipw30 zip30.new > test_zip_c.patch,然后输入cat test_zip_c.patch,检查生成的patch文件内容,参考图14:
在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: test Name: test Version: 1.2 Release: 3 License: GPL Source: http://downloads.sourceforge.net/infozip/zip30.tar.gz Source1: test-1.2.tar.gz Patch1: zip-3.0-exec-shield.patch # Not upstreamed. Patch2: zip-3.0-currdir.patch # Not upstreamed. Patch3: zip-3.0-time.patch Patch4: man.patch Patch5: zip-3.0-format-security.patch Patch6: zipnote.patch Patch7: zip-3.0-configure.patch Patch8: zip-3.0-covscan1.patch Patch9: test_zip_c.patch BuildRequires: bzip2-devel Requires: unzip %description test %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 %build make -f unix/Makefile generic_gcc refix=%{_prefix} LFLAGS2="$RPM_LD_FLAGS" CFLAGS_NOOPT="-I. -DUNIX $RPM_OPT_FLAGS" %{?_smp_mflags} %install tar xvf %{SOURCE1} --strip-components 1 -C $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_bindir} mkdir -p $RPM_BULD_ROOT%{_mandir}/man1 make -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 小明 <xiaoming@test.com> 1.2-3 - 增加zip源码压缩包及相关信息 * Sat Jun 5 2021 小明 <xiaoming@test.com> 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:
现在我们生成一个新的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:
现在我们再次生成新的patch, 命令行输入:diff -Naur zip30 zip30.new > test_zip.patch,然后 cat test_zip.patch,可以看到上次修改的内容。
执行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下的名称
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。