openSUSE:Build Service cross distribution howto
构建服务教学 - 技巧和花样 - 跨发行版打包 - Debian 打包指南 - 打包检查
桌面菜单分类 - 打包常用的 RPM 宏 - 小脚本片段 - SysVinit 脚本 - 源代码服务
OBS 打包互助问答 - 打包黑名单
目录
概览
本教学列出了使用一份 spec 文件来处理多个发行版所需要的特殊技巧。这不是针对新手打包者的,新手应该去看 构建服务指南。同样,本文档也不涵盖使用 蝶变软件包的发行版。
构建服务不但可以为 openSUSE 打包,还可以为最新的 SLES, CentOS, Fedora, Red Hat企业版, Ubuntu, Debian 和 Mandriva 发行版打包。
限制是什么? 唯一的现实限制就是有时无法满足 Fedora 或 Mandriva 的一些依赖关系,而这些在 openSUSE 中可以轻松的通过链入或嫁接其他的构建服务项目源来实现。比如:很容易在 openSUSE 下面编译需要最新版本的 Qt4 或 GTK2 的软件包,因为这些依赖关系可以由那些同样在构建服务上的,为老 openSUSE 版本和 SLES 版本提供更新 Qt4 包的其他源来满足。而对 Fedora 或 Mandriva 有时你就不得不在你的项目里先编译那些需要的依赖包了。(因为 SuSE 只储存了他们发行版的 ISO 内容,没有更新包。)这是你支持多发行版唯一会面临的问题。
你需要注意那些不同的发行版间的很明显的差别:
- 安装桌面文件。上述的五个发行版在安装桌面文件和创建菜单条目的方式都不一样。Mandriva 甚至使用了一个特殊的 RPM 宏 %update_menus 来完成该工作,这个宏做了更像 Debian 而不是 openSUSE 或者 Fedora 的配置。例如:
%post %update_menus %postun %clean_menus
- 依赖包的名字。下面的章节会告诉你一些技巧来在一个 spec 文件里支持很多不同的依赖包名字。
- RPM 宏变量之间的微妙差别。下面有个表格显示了这些不同。
你可以告诉我一个跨发行版软件包的范例吗?
使用特殊代码检测发行版
你可以添加:
%if 0%{?suse_version} <openSUSE 系的内容> %else <其他发行版的内容> %endif
来检测是否在为 openSUSE 系发行版打包。注意无法使用 %elseif 来在同一级命令中做多个 if 测试。你也可以更精确的检测 openSUSE 的版本:
%if 0%{?suse_version} > 1140
接下来就可以让 openSUSE 11.4 之后的任何 openSUSE 版本执行一些命令。同样的检测方法也可以检测其他发行版。
%if 0%{?fedora_version} > 15 %if 0%{?mandriva_version} > 2010
注意 RPM 更喜欢
>=
这样的表达方式而不是
=>
这样。你也可以使用代码来排除某个执行的发行版版本:
%if 0%{?suse_version} != 1140
你还可以使用 if 分隔符来混合检测多个发行版:
%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version} <针对上述发行版运行的命令> %endif
要想给检测条件分组,那么请把它们分散到几行,像这样:
# mono: 只在 openSUSE 和 SLES 10 以上的 SLES 里使用 %if 0%{?suse_version} %if 0%{?sles_version} == 0 || 0%{?sles_version} >= 1000 BuildRequires: mono-core %endif %endif
使用括号分组的方法在 fedora/rhel/centos 上会编译失败:
# mono: 只在 openSUSE 和 SLES 10 以上的 SLES 里使用 # 在 fedora RHEL centos 上编译会失败: %if 0%{?suse_version} && ( 0%{?sles_version} == 0 || 0%{?sles_version} >= 1000 ) BuildRequires: mono-core %endif
你也可以检测 CPU 架构:
%if 0%{?suse_version} == 1030 %ifarch x86_64 <在 64 位机上才会执行的一个命令> %endif %endif
下面是一些范式:
发行版 | 宏 | 注释 |
---|---|---|
openSUSE Factory | %if 0%{?suse_version} > 1210 | 目前的开发版,Tumbleweed 使用同样的宏 |
openSUSE 12.1 | %if 0%{?suse_version} == 1210 | |
openSUSE 11.4 | %if 0%{?suse_version} == 1140 | |
openSUSE 11.3 | %if 0%{?suse_version} == 1130 | |
openSUSE 11.2 | %if 0%{?suse_version} == 1120 | |
openSUSE 11.1 | %if 0%{?suse_version} == 1110 | 也可以用 SLE11 |
openSUSE 11.0 | %if 0%{?suse_version} == 1100 | |
openSUSE 10.3 | %if 0%{?suse_version} == 1030 | |
openSUSE 10.2 | %if 0%{?suse_version} == 1020 | |
SUSE Linux 10.1 | %if 0%{?suse_version} == 1010 | 也可以用 SLE10 |
SUSE Linux 10.0 | %if 0%{?suse_version} == 1000 | |
SUSE Linux 9.3 | %if 0%{?suse_version} == 930 | |
SLES 9 | %if 0%{?sles_version} == 9 | 也可以写成: %if 0%{?suse_version} == 910 |
SLE 10 | %if 0%{?sles_version} == 10 | 也可以写成: %if 0%{?suse_version} == 1010 |
SLE 11 | %if 0%{?sles_version} == 11 | 也可以写成: %if 0%{?suse_version} == 1110 |
CentOS 5 | %if 0%{?centos_version} == 504 | |
RHEL 4 | %if 0%{?rhel_version} == 406 | |
RHEL 5 | %if 0%{?rhel_version} == 501 | |
RHEL 6 | %if 0%{?rhel_version} == 600 | |
Fedora 6 with Extras | %if 0%{?fedora} == 6 | |
Fedora 7 with Extras | %if 0%{?fedora} == 7 | |
Fedora 8 with Extras | %if 0%{?fedora} == 8 | |
Fedora 9 with Extras | %if 0%{?fedora} == 9 | |
Fedora 10 with Extras | %if 0%{?fedora} == 10 | |
Fedora 11 with Extras | %if 0%{?fedora} == 11 | |
Mandriva 2006 | %if 0%{?mdkversion} == 2006 | |
Mandriva 2007 | %if 0%{?mdkversion} == 2007 | |
Mandriva 2008 | %if 0%{?mdkversion} == 2008 | |
Mandriva 2009.0 | %if 0%{?mdkversion} == 2009 | |
Mandriva 2009.1 | %if 0%{?mdkversion} == 200910 | |
Mandriva 2010.0 | %if 0%{?mdkversion} == 201000 |
特殊代码不能区分更新版SP。SLES11 SP2 使用跟 SLES11 同样的变量。
安装 info 文件
应该使用 %info 和 %info_del 宏来安装 info 文件。例如:
%post %info_add %{name}.info
%preun %info_del %{name}.info
请注意在一些发行版上 info 文件会被压缩成 .gz 或者 .bz2 甚至是 .lzma(最新的 Mandriva 就这么干)。你可以在 %file 文件列表章节使用 %ext_info 来表示 info 文件的后缀。
处理依赖关系
不同的发行版经常使用不同的软件包名字,所以 Requires: 和 BuildRequires: 标签的内容可能会因发行版而异。可以在源的配置文件里来指定包名替换,例如
%if 0%{?fedora} Substitute: libnetcdf-devel netcdf %endif
使用 osc meta prjconf <源名字> -e 命令可以打开你源的配置文件。网页客户端可以点击源主页的 Advanced - Project Config。
但是我们更建议使用这样的方法,在 spec 文件中:
%if 0%{?fedora_version} BuildRequires: netcdf %endif %if 0%{?suse_version} BuildRequires: libnetcdf-devel %endif
这样可以更具 RPM 精神,就是把所有的内容都藏在 RPM 中。不然编译是成功了,fedora 上面没有 libnetcdf 这个包,还是无法安装你的 RPM。
Suggests: 标签只适用于 openSUSE 10.0 以上
# 'Suggests:' 是一个 openSUSE 专有标签。因此不要把它用在其他发行版上,跨发行版请用 Recommends。 # 软件包本身不需要 vi 或 graphviz 就能运行。 %if 0%{?suse_version} > 1000 # 或许 920 和 930 也可以。sle9 910 肯定不行。 Suggests(建议安装): vim graphviz %endif
Fedora/RHEL 上查找 QT 3.x
Redhat/Fedora 使用了另一种命名方式和编译设置来使用 QT 编译其他软件。以下是个在同一 spec 中同时支持在 openSUSE 和 Fedora 上编译基于 QT 的软件的 spec 范式:
BuildRequires: cups cups-devel python-devel shared-mime-info libart_lgpl-devel libtiff-devel libxml2-devel BuildRequires: fontconfig-devel openssl-devel pkgconfig desktop-file-utils qt-devel %if 0%{?fedora} >= 5 BuildRequires: libstdc++-devel gcc-c++ lcms-devel >= 1.12 qt %endif %if 0%{?suse_version} > 910 BuildRequires: update-desktop-files %endif
然后还要:
%if 0%{?fedora} >= 5 source "%{_sysconfdir}/profile.d/qt.sh" %endif %configure \ %if 0%{?fedora} >= 5 --with-xinerama \ --with-extra-libs=%{_libdir} \ %endif %if 0%{?suse_version} > 910 --with-qt-libraries=/usr/%_lib/qt3/%_lib \ --with-docdir=%{prefix}/share/doc/packages/scribus \ %ifarch x86_64 ppc64 s390x --enable-libsuffix=64 \ %endif %endif <programoptions>
在 Mandriva 上查找 QT 4
默认的 QT3 的优先级比 QT4 高,所以添加下面的代码到你 spec 文件的 %build 章节才可以查找 QT4 。
%build %if 0%{?mandriva_version} > 2006 export PATH=/usr/lib/qt4/bin:$PATH export QTDIR=%{_prefix}/lib/qt4/ %endif
- 在 Mandriva 2008 里可能有变化。
使用 Provides/Obsoletes 来对 Mandriva 做特殊处理
处理 Mandriva 的时候需要特殊注意,不像 CentOS,RHEL,Fedora 或者 openSUSE,Mandriva 经常给软件切分出一个函数库子包,因此应用程序 foo 可能依赖 libfoo 或者 libfoo-0。所以,你应该检查一下 Mandriva 那边的 spec 文件,如果他们切包了,那么就需要使用 Provides 和 Obsoltes 来防止在 Mandriva 上安装冲突。虽然 RPM 可以自动处理依赖滚戏,你或许依然需要专门添加像下面几行的内容:
%if 0%{?mandriva_version} Provides: foo libfoo-0 Obsoletes: foo libfoo-0 %endif
在旧发行版版本上编译
有时候虽然源代码可以在老发行版版本上编译,但打包的方式却会造成不兼容。
比如,调用 autoreconf -fi(这在 spec 文件中很常见),因为调用了 -i 参数来安装,所以会导致源代码中使用上游开发者机器上的版本的 autoconf 包编译出来的 config.sub, config.guess 和 ltmain.sh 会被编译目标平台上的版本的 autoconf 包编译的同名文件替换掉。要是 SLE10 作为编译目标平台的话那就意味着 2012 年版本的 autoconf 生成的文件可能会被 2005 年版本的 autoconf 生成的文件替换掉,这些文件有时就会不能用,会让编译失败。
因此,最好,或者说,如果必须在 openSUSE_Factory 以下的 openSUSE 版本中使用 autoreconf 的话,你应该调用 autoheader,autoconf 而不是 autoreconf。下面是一个范式:
%if 0%{?suse_version} > 1010 autoreconf -fi %else autoheader autoconf %endif
蝶变 Debian 和乌斑兔 xUbuntu 软件包
针对 deb 格式的软件包我们有一个专门页面 蝶变打包指南 来讲。