openSUSE:构建服务技巧和窍门
本操作指南列出了一些使用构建服务的小技巧和窍门,这些技巧和窍门没有分类。这些技巧中的大部分都应包含在其他页面中并从这里删除。本网站的目的是为收集应尽快进行更多文档说明或修复的信息提供一个首要场所。
禁用软件包构建
有几种方法可以禁用单个软件包的构建。一种禁用软件包构建的方法是使用“osc”命令行客户端。只需使用
osc api -X POST "/source/PROJECT/PACKAGE?cmd=set_flag&flag=build&status=disable" # and later osc api -X POST "/source/PROJECT/PACKAGE?cmd=set_flag&flag=build&status=enable" # or better osc api -X POST "/source/PROJECT/PACKAGE?cmd=remove_flag&flag=build"
或编辑XML文件:
osc meta pkg -e <project> <package>
并在软件包的元数据中,在 <build> 标签内添加 <disable> 标签。您可以选择使用
<!-- [...] --> <build> <disable arch="<build-arch>"/> </build> <!-- [...] -->
或
<!-- [...] --> <build> <disable repository="<name-of-build-repository>"/> </build> <!-- [...] -->
或两者都使用,例如
<!-- [...] --> <build> <disable repository="SLES_9" arch="x86_64"/> </build> <!-- [...] -->
另一种方法是使用web客户端,并在显示相关软件包时点击相应的按钮。
注意: 已经开始的任务不会停止。要永久删除它们,您需要删除本地obs中/srv/obs/jobs/目录中的任务。
中止当前正在构建的软件包
osc abortbuild <project> <package> <repo> <arch>
扩展错误
如果软件包出现类似以下错误
expansion error have choice for inet-daemon needed by imap: inetd xinetd
您有两种选择:
- 快速修复方法是将上述软件包(inetd 或 xinetd)之一添加到您的 BuildRequires 中
- 另一种解决方法是在项目配置中设置首选项,使用: osc meta -e prjconf <Project> 并添加一行: Prefer: xinetd
- 长期修复方法是向 opensuse-buildservice 邮件列表发送邮件,并要求将其中一个文件添加到仓库的 .dsc 文件中,以便自动修复具有相同问题的其他软件包。
在项目中查找软件包
有时您希望找出软件包的名称,特别是在基本项目中,以便在 BuildRequires 行中使用它。有一个巧妙的 osc 调用可以找出它。
此命令
osc ls -b -r standard -a i586 Fedora:20
列出 Fedora 20 中的所有二进制软件包。从输出中选择软件包名称。
请参阅
osc ls --help
了解更多详细信息。
仅通过本地构建构建32位rpm
然后您可以在 x84_64 机器上本地构建一个 32 位软件包,尝试
osc build <TARGET> i586
您还可以创建 i586 二进制文件,这些文件可以在 x86_64 上通过 -32bit 后缀安装。要使其工作,您需要将 baselibs.conf(下面解释)添加到您的项目中。然后将参数 --baselibs 添加到您的 osc build 命令中。
osc build --baselibs <TARGET> i586
这还应该在您的 RPMS/ 目录中本地生成 -32bit 软件包,无需 OBS 的帮助。
权限拒绝错误
如果您的软件包在本地构建时没有任何问题,但在构建服务中构建相同的软件包时出现类似以下错误消息
/usr/bin/install: cannot create regular file `/usr/lib/libfoo.so.0.0`: Permission denied
请记住,构建服务目前仅支持在 chroot 环境中构建(并且您的软件包目前似乎没有使用 DESTDIR 或 RPM_BUILD_ROOT)。
只需在您的 spec 文件中添加一行
# norootforbuild
您将在本地构建环境中看到相同的(顺便说一句:丑陋的)失败:在提交到构建服务之前,请先修复这些错误...
_link 和 _aggregate
_link 和 _aggregate 之间的区别
为了避免重新构建那些仅作为其他软件包的构建要求或仅因为项目希望为最终用户分发完整软件包集而需要的软件包,构建服务中存在 _aggregate 功能。
通过 aggregate 链接到新项目中的软件包不会在新项目中重新构建,并且原始项目中的二进制文件将在它们更改时在新项目中更新。
以下是一些支持和反对 _link 或 _aggregate 的论点
| 理由 | _link | _aggregate | 评论 |
|---|---|---|---|
| 无需更改源代码。 | X | 可以进行聚合,但这会减慢构建速度并需要双倍空间。最好直接针对其他仓库进行构建。 | |
| 我的项目需要对源代码进行一些更改。 | X | ||
| 原始软件包无法在所有需要的发行版或架构上构建。 | X | X | 最好的方法是拥有两个不同的伪软件包:一个使用 _aggregate 功能,始终只从原始项目获取二进制软件包;另一个使用 _link 功能,为其余部分构建软件包。(但最简单的方法当然是要求原始维护者在他的项目中启用缺失的发行版/架构。) |
请务必不要将软件包链接与项目链接混淆,项目链接是构建服务的另一个功能。它在项目链接页面上进行了描述。
链接示例
简单 _link 示例
在您的项目中创建一个新软件包(名称可以与原始软件包相同——但这并非必不可少),并添加一个名为 _link 的文件,其内容如下:
<link project='openSUSE:Factory' package='tse3'/>
链接到另一个OBS实例
如果您正在运行本地 OBS 实例,并且只想从官方 Build Service 或任何其他具有可用 API 服务器的 OBS 实例链接一些软件包,请添加一个 _link 文件,如下所示:
<link project='openSUSE.org:openSUSE:Factory' package='tse3'/>
这将把来自 Build Service 实例 openSUSE.org 的 openSUSE:Factory 项目中的软件包 tse3 链接到您的项目中。
<remoteurl>https://api.opensuse.org/public</remoteurl>在项目定义中。无需进一步管理工作。
针对链接软件包的补丁
> Today I tried to link a package from another project to my project which > wasn't a problem. Then I checked out the new package with osc but I only > find a "_link"-file in the package dir. So how can I add a patch for > example or how can I modify the specfile?
文件可以单独添加到链接项目中。链接项目中的文件将替换原始项目中同名文件。这也包括 specfile。可以使用补丁文件来修补原始项目中的文件,而无需覆盖它们。补丁必须在 _link 文件中指定。
<link project='openSUSE:Factory' package='tse3'>
<patches>
<apply name="patch" />
</patches>
</link>
在链接软件包中添加补丁文件
要将新的补丁文件应用于源代码(除了 spec 文件中已列出的任何补丁文件之外),您可以为 spec 文件创建一个补丁,该补丁将补丁添加到 spec 文件中,并使用 <apply> 应用,但有更简单的方法,即使用 <add> 命令
<link project='openSUSE:Factory' package='tse3'>
<patches>
<add name="mybugfix.patch" />
</patches>
</link>
这会将 'mybugfix.patch' 添加到 spec 文件的待应用补丁列表中(这是通过构建服务为您插入相应的行到 spec 文件中来实现的)。新补丁将在 spec 文件中已定义的任何现有补丁之后应用。当然,'mybugfix.patch' 必须存在于您的链接项目中。
<add> 命令还支持属性 'popt="NUMBER"' 以向 %patch 添加 -pNUMBER 参数,'dir="some/dir"' 以在应用补丁之前更改到 some/dir,以及 'after="NUMBER"' 以在行号 NUMBER 之后添加 %patch。
在spec文件顶部添加一行
要在 spec 文件顶部添加一行(例如 %define),您无需修补 spec 文件。相反,您可以使用 <topadd>
<link project="myproject" package="theotherpackage">
<patches>
<topadd>%define small_build 1</topadd>
</patches>
</link>
要获取此文件,请使用 --unexpand-link 参数检出软件包,如下所示
之后,查找名为 _link 的文件,编辑该文件并将上面显示的代码片段添加到文件中。
要验证是否所有操作都成功,请在另一个位置检出软件包,并检查 spec 文件的顶部,它应该包含 <topadd> 标签之间的行。
来源和详情:[1]
聚合示例
_aggregate 示例
在您的项目中创建一个新软件包(名称可以与原始软件包相同——但这并非必不可少),并添加一个名为 _aggregate 的文件,其内容如下。请注意,_aggregate 通常被认为是糟糕的风格,因为项目需要双倍空间,构建服务可能会推迟您的软件包构建,并且不兼容的破坏风险相当高。通常,最好像下面解释的那样,针对更多仓库进行构建,以从其他仓库获取软件包。
<aggregatelist>
<aggregate project="KDE:Backports">
<package>ksimus</package>
</aggregate>
</aggregatelist>
如果仓库名称不匹配,您可以使用 <repository> 元素指定映射(source 是原始软件包的仓库名称)
<aggregatelist>
<aggregate project="KDE:Backports">
<package>ksimus</package>
<repository target="openSUSE_10.2" source="SUSE_10.2" />
<repository target="openSUSE_10.1" source="SUSE_10.1" />
</aggregate>
</aggregatelist>
完整语法示例
<aggregatelist>
<aggregate project="projectname" >
<package>glibc</package>
<package>libz</package>
<binary>gcc</binary>
<binary>gcc-c++</binary>
<nosources/>
<repository target="my_sle_11_repo" source="SLE_11" />
</aggregate>
<aggregate project="anotherproject" >
<binary>gcc</binary>
<repository target="my_sle_11_repo" source="SLE_11" />
</aggregate>
<aggregate project="lastproject" >
<package>glibc</package>
<repository target="my_sle_11_repo" source="SLE_11" />
</aggregate>
</aggregatelist>
在i586上选择i686软件包
如果您想要来自其他架构的软件包而不是默认架构(例如i586上的glibc i686),您需要
并添加
ExportFilter: \.i686\.rpm$ .
到您的项目配置中。
之后,使用类似以下命令
<aggregatelist>
<aggregate project="openSUSE:Factory">
<package>glibc.i686</package>
</aggregate>
</aggregatelist>
在i586上获取i686软件包。
向项目添加多个仓库
向项目添加多个仓库非常方便,如果一个软件包依赖(Requires 或 BuildRequires)多个 Build Service 仓库。
osc meta -e prj <project name>
这将打开项目元编辑器,在任何目标下使用 <path "projectname"/> 添加更多仓库。请注意,无需添加依赖仓库。以下示例仅从 openSUSE:Tools 项目添加了一个仓库。但是此仓库是针对 openSUSE:10.3/standard 仓库构建的,因此所有这些软件包也会被使用。
<repository name="openSUSE_10.3"> <path project="openSUSE:Tools" repository="openSUSE_10.3"/> <arch>i586</arch> <arch>x86_64</arch> </repository>
另一个例子:将 NonFree 和 Update 仓库添加到 openSUSE:10.2 项目。不需要基础 openSUSE:10.2/standard 仓库,因为它们都是针对它构建的。请注意,添加 :Update 项目通常会导致用户需要所有更新,否则他们会遇到麻烦,而为基础发行版构建应该适用于有更新和没有更新的用户。唯一需要 :Update 仓库的例外是内核模块(因为 Linux 内核经常变得不兼容,而所有其他软件包都不允许根据策略变得不兼容)
<repository name="openSUSE_10.2"> <path project="openSUSE:10.2:Update" repository="standard"/> <path project="openSUSE:10.2:NonFree" repository="standard"/> <arch>i586</arch> <arch>x86_64</arch> </repository>
请注意
- 包含仓库的顺序很重要:BuildService 将尝试使用包含该软件包的第一个仓库中的软件包,即使版本不匹配。
- 依赖项将递归包含。
- 用户必须在其系统中配置所有仓库,以便 zypper 可以在安装时解决 Requires:。如果您使用不常见的项目,则很难正确猜测它们。
- 最后的路径列表中的元素(但只有最后一个!)由构建服务“扩展”。这意味着所有由project=此元素的目标被隐式包含在项目中,并将被搜索以查找软件包。这旨在简化分支。
示例
项目 A 有
<repository name="openSUSE_Factory"> <path repository="snapshot" project="openSUSE:Factory"/> <arch>i586</arch> <arch>x86_64</arch> </repository>
您想在项目 B 中构建项目 A 的软件包。
要么使用
<repository name="openSUSE_Factory"> <path repository="openSUSE_Factory" project="A"/> <path repository="snapshot" project="openSUSE:Factory"/> <arch>i586</arch> <arch>x86_64</arch> </repository>
或者(由于 openSUSE:Factory/snapshot 已经从项目 A 中包含)
<repository name="openSUSE_Factory"> <path repository="openSUSE_Factory" project="A"/> <arch>i586</arch> <arch>x86_64</arch> </repository>
一个真实世界的例子,将 devel:languages:python 来源添加到您(现有)的仓库中
<repository name="openSUSE_12.1"> <path project="devel:languages:python" repository="openSUSE_12.1"/> <path project="openSUSE:12.1" repository="standard"/> <arch>i586</arch> <arch>x86_64</arch> </repository> <repository name="openSUSE_12.2"> <path project="devel:languages:python" repository="openSUSE_12.2"/> <path project="openSUSE:12.2" repository="standard"/> <arch>i586</arch> <arch>x86_64</arch> </repository>
构建环境是如何定义的?
它在 build 软件包的 /usr/lib/build/configs/$distro.conf 中定义。这里有关于此文件中字段的描述
这就是关于构建环境设置的全部知识。哦,我们还在这里进行依赖项扩展,因此由于软件包依赖项而需要的软件包会自动添加到“Required”列表中。
构建需要在构建期间使用X-Server的软件包
> the package XXXXXX requires an X-server (or > at least a DISPLAY) to build (without changing the configuration > files). > > Can I access an X-Server in the buildservice? > What are the required changes in my spec file? You can run an Xvfb (start it in your specfile) to workaround this problem.
例如,您可以在您的 specfile 中使用以下代码行
BuildRequires: xorg-x11-server
%define X_display ":98"
...
%install
#############################################
### Launch a virtual framebuffer X server ###
#############################################
export DISPLAY=%{X_display}
Xvfb %{X_display} >& Xvfb.log &
trap "kill $! || true" EXIT
sleep 10
...
# start your application/testsuite here
为不同平台使用不同的spec文件
在一个理想的世界中,您将拥有一个在过去、现在和未来的所有基于 RPM 的平台上都能工作的单一 spec 文件。然而,在现实中,通常单个 spec 文件要么不可能,要么需要您在 spec 文件中进行如此多的 %if 分支,以至于它变得不可读。
幸运的是,构建服务有一种方法可以为单个平台使用多个 spec 文件。
假设您有一个名为“foo”的软件包,其中包含一个名为“foo.spec”的 spec 文件。让我们假设这个 spec 文件对于 openSUSE、SLES 和 SLED 等基于 SUSE 的发行版非常有效,但软件包布局的差异意味着您确实需要一个单独的 spec 文件来构建像 Fedora 这样完全不同的发行版。如果构建服务中的仓库名为“Fedora_Extras_6”,您可以创建一个名为“foo-Fedora_Extras_6.spec”的 spec 文件,该文件将仅为该平台构建,而不是使用“foo.spec”。
这唯一的缺点是它只适用于单个仓库。无法为多个仓库使用单个 spec 文件。回顾上面的例子,如果您想为 Fedora Extras 4、5 和 6 构建“foo”,您将不得不创建三个 spec 文件:“foo-Fedora_Extras_4.spec”、“foo-Fedora_Extras_5.spec”和“foo-Fedora_Extras_6.spec”,即使这些 spec 文件完全相同。
一个实际使用此功能的很好示例是 net-snmp 项目中的“net-snmp-main-snapshot”软件包。
从仓库中删除已禁用但已构建的软件包
目前 Webfrontend 不支持此功能。在 osc 中,只需键入
osc wipebinaries <projectname>
您也可以直接与 buildservice-API“对话”以解决此问题。如果您想删除整个仓库中所有标记为已禁用的已构建 rpm(在此示例中:home:foo),请尝试以下方法
- 创建包含您的 build.opensuse.org 登录信息的 ~/.netrc 文件,或者使用 "-u username:password" 选项。
curl -n -X POST -d '' 'https://api.opensuse.org/build/home:foo?cmd=wipe&code=disabled'
或curl -u username:password -X POST -d '' 'https://api.opensuse.org/build/home:foo?cmd=wipe&code=disabled'
有关更多“命令”,请查看 API 文档。
列出发行版中可用的软件包
当您不知道构建所需的软件包的确切名称时,可以使用 网页搜索 或 osc ls -b。
示例:哪个软件包在 Ubuntu 上包含 mysql 开发文件?
# <repository> <arch> <project> $ osc ls -b -r standard -a i586 Ubuntu:7.10 | grep 'mysql.*dev' libmysqlclient15-dev_5.0.45-1ubuntu3_i386.deb # -> the package is called "libmysqlclient15-dev"
在构建服务仓库中启用rpmlint检查
请查看 页面和 。
为其他架构构建xx位软件包 (baselibs)
参阅 openSUSE:Build Service_baselibs.conf
如何控制生成软件包的发布版本号
通常 BuildService 会自动处理 Release 标签,因此 Release: 字段的内容会被 CI_CNT.B_CNT 元组替换,其中 CI_CNT 是提交次数,B_CNT 是重新构建次数(当触发重新构建时)。
此行为等同于
Release: <CI_CNT>.<B_CNT>
在 prjconf 中(可通过 osc meta prjconf -e [PROJECT] 访问)。
您可以改进它。例如,对于 jpackage.org RPM 的导入,您可以在 prjconf 中定义
Release: %%{?release_prefix}.<CI_CNT>.<B_CNT>
其中 rpm 宏 %{release_prefix} 在 spec 文件中定义。生成的 rpm 将具有与 jpackage.org 和 openSUSE 项目兼容的发布版本号。这意味着您将能够将您的 SUSE 软件包升级到 jpackage.org 的软件包。
或者在您的 specfile 中,如果您的软件包是由 jenkins job 123 生成的,您可以直接说
Release: <CI_CNT>.<B_CNT>.j123
生成的 rpm 的普通构建发布号将附加 '.j123',以便您以后可以查看启动构建的 jenkins job。
另请参阅 OBS 手册中关于构建配置的章节。
尝试删除项目时如何修复“不存在”错误
当后端超时时,API 数据库和后端之间可能会出现不一致的状态。要删除此类项目,只需使用 osc 编辑其元文件
osc meta prj -e <projectname>
保存它,然后删除它
osc rdelete <projectname>
构建 SLES 11 SP1 LiveCD
经测试,使用 kiwi-3.74-5.101.1 在构建系统上安装 clicfs-1.1.3-3.1.x86_64.rpm 和 liblzma0-4.999.9beta-11.1.x86_64.rpm,并将这些文件复制到您在 /usr/share/kiwi/image/isoboot/suse-SLES11/config.xml 中配置的仓库目录。
修改文件 /usr/share/kiwi/image/isoboot/suse-SLES11/config.xml 并在 <packages type="bootstrap"> 部分添加以下行 <package name="clicfs"/>
这可能是一个bug,使用这行(CD无法启动)不起作用
<packages type="bootstrap" profiles="std">
但使用 type=image,CD 运行正常。
<packages type="image" profiles="std">
- kiwi --createhash /usr/share/kiwi/image/isoboot/suse-SLES11
修改您的 Live CD 的 config.xml(而不是您刚刚编辑的 config.xml)以使用 clicfs:<type primary="true" boot="isoboot/suse-SLES11" flags="clic">iso</type>
使用 squashfs 和 aufs 设置 SLES 10 SP2/SP3 KIWI 镜像
我的构建主机也是 SLES 10 SP2 x86_64。
这只是一个快速指南,请参阅其他 KIWI 文档。
步骤1 安装KIWI
注意:您可能会在 SLES 10 SDK 仓库中找到一些软件包。我从以下地址安装了当前的 kiwi-3.01-93.1
http://download.opensuse.org/repositories/openSUSE:/Tools/SLE_10
注意:对于 kiwi-desc-oemboot 和 kiwi-desc-vmxboot,您需要 qemu,我没有安装它们。
安装智能包管理器
rpm -ivh /usr/share/kiwi/repo/suse-repo/suse-sle10-repo/smart-0.41-23.4.$(arch).rpm
从 http://download.opensuse.org/repositories/home:/mopp:/squashfs/ 下载 SLES 10 SP2/SP3 的 squashfs
从 http://download.opensuse.org/repositories/home:/mopp:/aufs 下载 SLES 10 SP2/SP3 的 aufs
在 KIWI 服务器上安装 squashfs 软件包
rpm -ivh /tmp/kiwi/squashfs-3.4-35.1.x86_64.rpm
步骤2 创建KIWI引导镜像环境
当然,您需要 SLES 10 SP2/3 源,我将它们复制到本地目录。将路径更改为适合您系统的目录。
cp -a aufs-kmp* squashfs-kmp* /usr/share/kiwi/repo/suse-repo/suse-sle10-repo/
注意:aufs 和 squashfs 模块安装在 /lib/modules/<kernel>/updates/。请确保内核模块与您在 KIWI 镜像中安装的内核匹配。
现在是修改 config.xml(boot/initrd 镜像)以查找 aufs 和 squashfs 模块的时候了。也许您可以在编辑之前复制目录,因为更新 kiwi 后 config.xml 可能会被覆盖。
cd /usr/share/kiwi/image/isoboot/suse-SLES10 vi config.xml
非常重要的是将 aufs 和 squashfs 添加到 <drivers type="drivers"> 部分,添加这些行,否则 LiveCD 将无法找到。
<file name="../updates/aufs.ko"/> <file name="../updates/fs/squashfs/*"/>
在 <packages type="bootstrap"> 部分添加以下行
<package name="squashfs-kmp-default"/> <package name="squashfs-kmp-smp"/> <package name="aufs-kmp-default"/> <package name="aufs-kmp-smp"/>
创建新的哈希
kiwi --createhash /usr/share/kiwi/image/isoboot/suse-SLES10
步骤3 准备系统镜像
确保您不要混淆引导镜像内核和系统镜像内核之间的内核(-default 和 -smp)。
准备系统镜像(我使用了 suse-11.0 配置,因为它是一个最小配置)
cp -pr /usr/share/doc/packages/kiwi/examples/suse-11.0/suse-live-iso /usr/local/kiwi/suse-sle10sp2-live-iso
编辑 /usr/local/kiwi/suse-sle10sp2-live-iso 中的 config.xml,至少您必须更改 "boot" 标签和 "repository"
更改
<type primary="true" boot="isoboot/suse-11.0" flags="unified">iso</type>
到
<type primary="true" boot="isoboot/suse-SLES10" flags="unified">iso</type>
删除软件包 "bootsplash-branding-openSUSE",因为它在 SLES 10 上不可用。
您需要添加仓库以查找其他软件包,例如 smart。
<repository type="rpm-dir">
<source path="/usr/share/kiwi/repo/suse-repo/suse-sle10-repo/"/>
</repository>
在 config.xml 中添加或删除您需要的软件包并自定义您的系统。
您可以添加 dhcpcd 软件包以启用 dhcp。
opensusePattern 似乎不适用于 SLES。
步骤4 创建ISO镜像
确保您有足够的可用空间。
kiwi --prepare /usr/local/kiwi/suse-sle10sp2-live-iso --root /tmp/myiso
检查日志文件。要检查创建的目标系统,您可以执行
chroot /tmp/myiso
如果一切正常,是时候创建 iso 镜像了
kiwi --create /tmp/myiso -d /tmp/myiso-result
检查日志文件。
尝试启动 iso 镜像
从VCS检出执行夜间构建
如果您想使用 _service 文件技术并避免解析/编辑 .spec 文件,甚至允许与 Debian 打包共享版本信息,请尝试 https://github.com/boombatower/obs-git-update。否则,请继续阅读。
您需要一台装有 cron 和 osc 的机器。
准备一个工作目录,其中包含您的代码的 VCS 检出和构建服务中软件包的检出。准备一个 spec 文件模板,并在版本字段中放置一个占位符。它可能看起来像这样
Name: monitord Version: ##TIMESTAMP## Requires: alsa ...
准备一个 shell 脚本,用于本地更新、准备 tarball、修改 spec 文件并将文件上传到构建服务。
这是一个 SVN 仓库的示例脚本
#!/bin/bash # the relative path to the OBS checkout PACK_PATH=home:cwh:monitord-nightly/monitord # the relative path to the SVN checkout REPO_PATH=trunk TIMESTAMP=`date +"%Y%m%d"` # enter SVN directory pushd $REPO_PATH # update to current revision svn up # prepare tarball make dist # move resulting tarball to the package directory cp monitord-2.0svn.tar.gz ../$PACK_PATH popd # copy a modifyed spec file to the package directory perl -p -e "s/##TIMESTAMP##/$TIMESTAMP/" monitord.spec > $PACK_PATH/monitord.spec # enter package directory pushd $PACK_PATH # upload changes (new tarball and spec file) to the OBS osc commit -m "updated to current SVN snapshot $TIMESTAMP" popd echo "Done"
然后通过 cron 调用此脚本。
示例
0 5 * * * cd /space/monitord-nightly && ./push_to-obs.sh