Home Wiki > openSUSE:Build Service cross distribution howto
Sign up | Login

openSUSE:Build Service cross distribution howto

tagline: 来自openSUSE

概览

本教学列出了使用一份 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 宏变量之间的微妙差别。下面有个表格显示了这些不同。

你可以告诉我一个跨发行版软件包的范例吗?

Amilcar 的 KDevelop 软件包

使用特殊代码检测发行版

你可以添加:

%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 的话,你应该调用 autoheaderautoconf 而不是 autoreconf。下面是一个范式:

%if 0%{?suse_version} > 1010
  autoreconf -fi
%else
  autoheader
  autoconf
%endif

蝶变 Debian 和乌斑兔 xUbuntu 软件包

针对 deb 格式的软件包我们有一个专门页面 蝶变打包指南 来讲。

其他发行版的 RPM 宏变量和相关文档

openSUSE 打包指南

Fedora 打包者指南

Mandriva 打包指南

RHEL,Mandriva,Suse RPM 宏变量的比较