Perl 打包
构建服务教学 - 技巧和花样 - 跨发行版打包 - Debian 打包指南 - 打包检查
桌面菜单分类 - 打包常用的 RPM 宏 - 小脚本片段 - SysVinit 脚本 - 源代码服务
OBS 打包互助问答 - 打包黑名单
目录
编译工具
cpanspec
cpanspec 或许是最好的把 CPAN 上的软件包移植到 openSUSE 构建服务上的工具。下面是一个实例流程,在构建服务上打包 perl 模块 File::LibMagic :
# add devel:languages:perl zypper ar http://download.opensuse.org/repositories/devel:/languages:/perl/openSUSE_11.2/devel:languages:perl.repo zypper in cpanspec cd your_checked_out_build_service_project osc mkpac perl-File-LibMagic cd perl-File-LibMagic cpanspec -v File::LibMagic osc build --local # vi *.spec ... BuildRequires: perl(Other::Package) BuildRequires: libfile-devel ZZ osc ci
cpanspec 会从 CPAN 网络下载 tar 压缩包,分析它,然后创建 perl-File-LibMagic.spec 和一个初始的 *.changes 文件。cpanspec 在 devel:languages:perl 源中维护。
和原始的潘多拉版本 [1] 不同,这个版本被补缀以适应我们的构建服务的需要。
cpanspec_obs
一个额外的多了点东西的脚本,cpanspec_obs 可以用来全自动化一些简单的 perl 模块包。你只需要导航到 obs 项目的本地目录中,然后调用 cpanspec_obs 带上准确的 CPAN 包名,接着使用 osc 提交即可。
cpan2spec
常见错误叫法。人们说 'cpan2spec',实际上他们的意思是说 'cpanspec'。
cpan2dist
打包 perl 模块的 spec 范式文件书写这个过程可以被 cpan2dist 简化。它和例如 perl-5.10.0 捆绑分发,可以在 CPAN 获得升级。开发环境架设在 github。
这是个为构建服务打包 perl 模块 File::LibMagic 的实例流程:
# add devel:languages:perl zypper ar http://download.opensuse.org/repositories/devel:/languages:/perl/openSUSE_11.2/devel:languages:perl.repo zypper in perl-CPANPLUS-Dist-RPM zypper in perl-CPANPLUS-Dist-SUSE
cd your_checked_out_build_service_project osc mkpac perl-File-LibMagic cd perl-File-LibMagic cpan2dist --format CPANPLUS::Dist::SUSE File::LibMagic osc vc perl-File-LibMagic osc add File-LibMagic*.tar.* perl-File-LibMagic.{changes,spec} osc build --local-package # vi *.spec osc ci
CPANPLUS::Dist::SUSE 的 0.01 版本里,以下条目需要注意:
- Group 应该是: Development/Libraries/Perl (还行,只丢了 "/Perl").
- BuildRequires: 那些非 perl 的编译依赖软件包 (通常是 *-devel) 被省略掉了。
- Requires: perl 软件包经常丢这些。检查 Makefile.PL 并补上。
- %install 章节不应该做 rm -rf %{buildroot}
- %install 章节触摸了一个空的 %{buildroot}/%{_mandir}/man3/*.3pm.gz
- %install 章节没有 %perl_process_packlist
- %install 章节没有 %perl_gen_filelist
- %files 章节应该使用 %files -f %{name}.files
- %bcond_with 检测
%if %{with test}
可以用来触发一个非常非常慢的编译检查,可选。(osc build --with test)
- %description: 没有描述
- License: GPL-2.0 或 GPL-3.0
非官方版本 0.01.3 可从 devel:languages:perl 获取,修复了以上大多数。 它也添加了一些 BuildRequires: 和实验性的标签:
BuildRecommends: perl(Test::CheckManifest)
这不会造成错误,但我从来没见过它把 Test::CheckManifest 拉进编译过程。 如何写 Requires: 标签呢?如果它在编译时需要?
与添加一份 tar 压缩包的副本作为源代码不同,而是会使用一个链接到 CPAN 网络上的原始 tar 压缩包地址的 _service 链接。参考 devel:languages:perl:CPAN 获得更多信息。
Perl 模块使用什么授权协议
绝大部分 perl 模块都在 README 文件的底部带了关于授权协议的简短说明。有时候授权协议也写在源代码包里的 LICENSE 或 COPYING 文件中。如果 perl 模块的协议说明中说 与 Perl 自身的协议相同 (这种情况很常见),那么 spec 范式文件中的 License 标签应该写成:
License: Artistic-1.0 or GPL-1.0+
如果授权协议不是 “和 Perl 自身的协议相同” 那么应去 openSUSE:Accepted_licences#Good_Licenses 页面选择正确的 spec 文件 License 标签授权协议缩写 ( Short Name 分类提供了在 spec 文件中使用的协议缩写)。 更复杂的授权协议情况可以到 the Fedora Packager's Licensing Guidelines 页面找到更多的指导。
这里有 openSUSE 支持的所有授权协议: license.opensuse.org
用于 perl 模块的 RPM 宏
(来自 en.opensuse.org/Packaging/SUSE_Package_Conventions/RPM_Macros)
%if 0%{?suse_version} < 1120 BuildRequires: perl-macros %endif
如果是针对 openSUSE 1120 以下的版本打包,请添加上述的 BuildRequires,不然你会得到如下错误提示
+ %perl_gen_filelist /var/tmp/rpm-tmp.6091: line 40: fg: no job control
%perl_archlib
许多 perl 软件包都是纯 perl 的。因此可以用 noarch 编译。如果可能的话,添加下面这个标签和值到你的 spec 范式文件:
BuildArch: noarch
如果不能用 noarch 编译的话, %perl_archlib 宏就对你很有用了。
该宏最终会被 perl 模块中和操作系统架构相关的部分的安装路径替代,例如, /usr/lib/perl5/5.8.5/i586-linux-thread-multi
。
它通常只用于 perl
软件包本身,和 %perl_process_packlist
宏。并不直接使用,也就是说它是一个供机器阅读的中间宏,详情见下。
%perl_make_install
该宏能在各种不同的 openSUSE 产品上正确的调用 make install 操作。在 SL 9.0 之前,通常调用它的方法是:
make PREFIX=$RPM_BUILD_ROOT/%_prefix \ INSTALLMAN1DIR=$RPM_BUILD_ROOT/%_mandir/man1 \ INSTALLMAN3DIR=$RPM_BUILD_ROOT/%_mandir/man3 \ install
针对 9.0 和之后版本:
make DESTDIR=$RPM_BUILD_ROOT install_vendor
使用 %perl_make_install
宏,会根据系统版本相应的使用上面做法中的一种。
下面实例出自 perl-URI
:
%install %perl_make_install
%perl_process_packlist
该宏为最终的软件包准备了与 perl 模块相关的一些文件。它做了如下操作:
- 从
%perl_archlib/perllocal.pod
中删除了$RPM_BUILD_ROOT
并把该文件重命名为软件包相关的名字。详情见下。 - 搜索安装的
.packlist
文件并从它们当中删除$RPM_BUILD_ROOT
字段。
每个提供 perl 模块的软件包都应该在 %install
章节调用此宏。
%perl_archlib/perllocal.pod
文件必须被重命名因为它包含了额外安装的 perl 模块的相关信息,因此不能被多个软件包共用。所以,它被重命名了,并且一个特殊的 SuSEconfig 模块, /sbin/conf.d/SuSEconfig.perl
, 会在软件包安装完成后链接重命名的文件里面的信息到系统的 %perl_archlib/perllocal.pod
文件。
实例出自 perl_URI
:
%install %perl_make_install %perl_process_packlist %files [...] /var/adm/perl-modules/%{name}
%perl_gen_filelist
自 11.2 起(或者使用 BuildRequires: perl-macros 标签),可以实现更多的自动化操作:
%install %perl_make_install %perl_process_packlist %perl_gen_filelist %files -f %{name}.files %defattr(-,root,root,-) %doc README CHANGES COPYING
注意该宏不能找到没安装的文件。因此我们依然使用 %doc 来直接从源代码树里搜集重要的文档文件。
%perl_sitearch
该宏最终被本地系统管理员把 perl 模块的操作系统架构相关的文件安装到的路径所替代 (/usr/lib/perl5/site_perl/5.8.5/i586-linux-thread-multi
)。openSUSE 分发的软件包则使用了 %perl_vendorarch
宏定义的路径。见下。
%perl_sitelib
该宏指代了本地管理员将 Perl 模块中与操作系统架构无关的部分安装到的路径 (/usr/lib/perl5/site_perl/5.8.5
)。
随 SuSE 分发的软件包应该使用 %perl_vendorlib
宏定义的路径。(见下)
%perl_vendorarch
该宏最终被 LINUX 发行版将 perl 模块的操作系统架构相关部分安装到的路径所替代 (/usr/lib/perl5/vendor_perl/5.8.5/i586-linux-thread-multi
)。该宏的典型使用是在文件列表章节。实例来自 perl-URI
:
%files [...] %{perl_vendorarch}/auto/URI
该路径自 SL 9.0 起使用。在那以前,perl 模块是被 %perl_sitearch
宏安装到 /usr/lib/perl5/site_perl
路径的。site_perl
目录目前被用于由本地系统管理员安装的模块 (参见上面的 %perl_sitearch
)。
%perl_vendorlib
该宏最终被 Linux 发行版将 Perl 模块与操作系统架构无关的部分安装到的路径所替换(/usr/lib/perl5/vendor_perl/5.8.5
)。该宏的典型使用在文件列表中。实例来自 perl-URI
:
%files [...] %{perl_vendorlib}/URI.pm %{perl_vendorlib}/URI
该路径自 SL 9.0 起使用。之前,Perl 模块被安装到 %perl_sitearch
宏安装到 /usr/lib/perl5/site_perl
目录。该目录 site_perl
目前用于那些被本地系统管理员安装的模块 (见上述的 %perl_sitelib
)。
%perl_version
该宏会返回编译软件包使用的 Perl 的版本,例如 5.8.5
。它被用于在那些提供 perl 模块的软件包中定义对 Perl 的依赖。
在老旧的软件源中,一般是 SLES,它通常这样使用:
Requires: perl = %{perl_version} # 现在已被 %perl_requires 宏替代
%perl_requires
自从 11.4 起,对目前版本的 perl 的运行依赖应该这样子写:
%if 0%{?suse_version} < 1140 Requires: perl = %{perl_version} %else %{perl_requires} %endif
在 11.4 以前,我们需要一个额外的使用了 %perl_version 宏的 'Requires' 标签。
请注意,使用该宏时,11.3 上的 quilt 就不好使了。
%__perl
返回系统上安装的 perl 的名称。
%perl_gen_filelist
生成一个名为 %[name}.files 的包含了所有被安装到 %{buildroot} 的文件的列表。这可以用来简化后面的 %files 文件列表章节。在 %install 章节的末尾调用该宏:
%install [...] %perl_process_packlist %perl_gen_filelist
注意该宏并不能探测到没有被安装的文件。因此我们依然需要使用 %doc 标签来从源代码目录里搜集那些比较重要的文档文件。你的 %files 章节可能和下面的这个一样简单:
%files -f %{name}.files %defattr(-, root, root, -) %doc Changes README COPYING
这是很有帮助的。如果你的 %{perl_vendorarch}/* 的写法实际上包含了 '*/auto' 目录,用 %exclude 又会使用大量的匹配,那么请看下面的例子。
rpmlint 的一些相关错误以及误报
auto directory is included
如果编译过程中止在:
... running 04-check-filelist ... checking filelist perl-File-MMagic-XS: auto directory is included in the perl package
这个错误多见于你的 spec 范式文件中有这样一行:
%files [...] %{perl_vendorlib}/*
要是使用 perl-5.10.0 中的 cpan2dist 创建 spec 范式文件,默认的情况下一般都会遇到这个问题。 上述写法占有了 %{perl_vendorlib}/i586-linux-thread-multi/auto 文件夹,如果你的软件包内有一些 .so 的函数库,那么它自身就必须不能占有 '*/auto' 文件夹, 只能拥有里面的内容和子文件夹。
%files [...] %{perl_vendorlib}/*/auto/* %{perl_vendorlib}/*/File %{perl_vendorlib}/*/File/*
上述改动适用于 File::* 模块。也可以使用上述的 %perl_gen_filelist 宏来获得一个更好的可能的解法。
链接失败,错误: undefined reference to "function name"
如果您得到「未定义的指向(undefined reference)」系列错误,但实际上需要的函数库是定义过的,这就意味着链接顺序不对。openSUSE > 1110 版本中的所有函数库都是在需要时(--as-needed)通过 ld 标记来实时链接的。让我们看一个小例子:
假设你编译了一个静态函数库 libwurst,它的主函数中使用了 pow() 函数。
$ gcc -Wl,--as-needed --static main.c -o wurstsalat -L. -lm -lwurst ./libwurst.a(wurst.o): In function `wurst': wurst.c:(.text+0x29): undefined reference to `pow'
这里的问题出在,链接器(ld)不能在 main.c 中找到任何 pow() 的指向。然后第一个函数是 libm,由于它没被用到,链接器忽略了它和它之后的所有 -l 链接。所以你需要在链接 libm 之前链接 libwurst.a。
$ gcc -Wl,--as-needed --static main.c -o wurstsalat -L. -lwurst -lm
简单总结: 当使用 --as-needed 参数时,命令行中函数库的出现顺序是严格相关的:提供 X 使用的符号的所有函数库 X 必须在所有函数库 Y 之前。
如果你的软件包非常复杂,或者你缺乏制作这类补丁的经验,添加下面一行到你的 %build 章节:
export SUSE_ASNEEDED=0
这会忽略 --as-needed 参数。
详情参考 http://www.gentoo.org/proj/en/qa/asneeded.xml#doc_chap2