创建 Alpine 软件包
此页面记录了在 Alpine Linux 中创建和提交新软件包的步骤。
概述
这是在 Alpine Linux 中创建和提交新软件包的简要步骤列表。请参阅本 wiki 的其余部分以了解步骤的详细信息。
- 在 https://gitlab.alpinelinux.org 上创建一个账户
- 设置构建环境.
- Fork aports 仓库 并 克隆你的 fork 。
- 设置 git pull.rebase=true,配置你的 git 用户名和电子邮件。
- 创建并切换到一个新分支(不要使用 master)。
- 在 testing 下添加一个新目录,作为你的新软件包名称。
- 添加你的 APKBUILD 文件。
- 运行 abuild checksum
- 确保你运行了 apkbuild-lint 和 aport -r,并且没有警告。
- 提交你的 APKBUILD,提交信息为:'testing/packagename: new aport'
- 将你的更改推送到你在 https://gitlab.alpinelinux.org/alpine 上的 fork。
- 创建一个合并请求。
要求
设置你的系统和账户 以在 Alpine Linux 中构建软件包。如果你还没有 Alpine Linux,请参考 设置构建环境。
获取帮助
abuild 软件包提供了为 Alpine Linux 创建软件包所需的脚本。它实现了构建软件包的功能,以及用于软件包维护的附加命令和选项。明智的做法是从检查 abuild 程序可以/不能做什么开始。
abuild -h
如需实时帮助,你也可以访问 IRC 上的 #alpine-devel。
APKBUILD 文件的参考文档可以在 APKBUILD 参考 wiki 页面或 abuild-doc 软件包中的 man 页面中找到
man APKBUILD
创建 APKBUILD 文件
APKBUILD 示例 页面列出了许多 APKBUILD 示例,范围从 简单 APKBUILD 到 子软件包 以及各种 应用程序特定示例。这些示例将帮助你理解如何创建 APKBUILD,并提供可在你自己的 APKBUILD 文件中使用的代码片段。
使用模板 APKBUILD
Alpine Linux 提供了以下工具来创建模板 APKBUILD 文件。
newapkbuild
newapkbuild
工具作为 abuild 软件包的一部分安装,可以生成一个新的 APKBUILD 模板作为起点。手册页(可通过 man newapkbuild
获得)描述了 newapkbuild
的所有选项。
如果你不确定你的软件包属于哪个仓库,你可以安全地使用 testing。在你的 aports/testing 目录中构建软件包不是强制性的,但这样软件包就已经在正确的位置了。
以下命令将创建一个以给定软件包名称命名的目录,在该目录中放置一个示例/模板 APKBUILD 文件,并在提供的情况下填充一些变量。
newapkbuild packagename
如果你正在创建一个需要 initd 脚本的守护程序软件包,你可以添加 -c 选项,如下所示
newapkbuild -c packagename
这将复制示例 initd 和 confd 文件到构建目录。第三个文件 sample.install 文件也将被复制(我们稍后会讨论这个)。
apkbuild-cpan
Comprehensive Perl Archive Network (CPAN) 提供了大量的 perl 软件和文档。apkbuild-cpan有助于为来自 CPAN 的 perl 模块创建 APKBUILD。
apkbuild-cpan [create <Module::Name> | check | recreate | update | upgrade]
此命令由 apkbuild-cpan 软件包提供。
apkbuild-pypi
Python Package Index (PyPi) 是 Python 编程语言的软件和库的仓库。apkbuild-pypi
命令有助于为托管在 PyPI 上的 python 软件包创建 APKBUILD。
apkbuild-pypi [create <package> | check | recreate | update | upgrade
此命令由 apkbuild-pypi 软件包提供。
修改你的 APKBUILD
编辑 APKBUILD 并填写所需信息(特别是 pkgname、pkgver、pkgdesc、url、license、depends 和 source)。
如果你要使用任何目录变量,如 $pkgdir,请始终确保它们用双引号括起来,例如
"$pkgdir"/somedir
这将防止将来出现空格/特殊字符问题。
APKBUILD 变量/函数
source
source 变量不仅用于列出要获取的远程源文件,还用于列出 abuild 构建 apk 所需的本地文件。此类本地文件的示例包括:init.d 文件、conf.d 文件、install 文件(参见 install 变量)、补丁和所有其他必要文件。
以下是一些注意事项
- 当你完成向 source 添加本地和/或远程文件后,你可以执行以下命令将它们的校验和添加到 APKBUILD 文件
abuild checksum
- 注意: 当稍后更新 source 的内容,或更新 source 中列出的文件时,你还必须使用相同的命令再次更新它们的校验和。
- 当远程文件托管在 SourceForge 上时,最好指定 SourceForge 使用的特殊镜像链接
http://downloads.sourceforge.net/$pkgname/$pkgname-$pkgver.tar.gz
- (或类似的,取决于软件包)。
- 当 URI 中未指定远程文件名时(即,不以 '/software-1.0.tar.gz' 结尾),例如
http://oss.example.org/?get=software&ver=1.0
- 你必须将 '${pkgname}-${pkgver}.tar.gz::' 前置到协议,如下所示
source="${pkgname}-${pkgver}.tar.gz::http://oss.example.org/?get=software&ver=1.0"
- 这会导致文件保存为 software-1.0.tar.gz,abuild 可以使用它,而不是 ?get=software&ver=1.0,abuild 无法使用它。
- 有些项目没有提供发布 tarball。请注意,某些 git 服务(gitweg、cgit、…?)不提供稳定的 tarball,因此当你将 source 指向类似这样的 tarball 时https://repo.or.cz/w/gitstats.git/snapshot/ad7efbb9399e60cee6cb217c6b47e604174a8093.tar.gz,那么你将遇到问题,因为在构建系统上下载时校验和会更改。这在 GitHub、GitLab 和其他体面的服务提供商上不是问题,它们提供稳定的 tarball。
- abuild 当前支持以下用于远程文件检索的协议
- http
- https
- ftp
- abuild 当前支持以下存档类型/存档文件扩展名
- .tar
- .tar.gz / .tgz
- .tar.bz2
- .tar.lz(仅在 Alpine >=3.7 中)
- .tar.lzma
- .tar.xz
- .zip
depends & makedepends
Depends 是软件包运行时需要的实际运行依赖项。Makedepends 仅在构建软件包时需要。如果你在 depends 中设置了一个软件包,则无需将其添加到 makedepends 中。找出软件包的 depends 和 makedepends 的最佳方法是 RTFM。
不开玩笑,许多重要信息可以在软件包的 INSTALL 和 README 文件(或类似文件)中找到。另一种好方法是从源目录运行 ./configure --help
,以查看完成配置而不会出错需要哪些选项。如果你还没有源目录,你可以使用以下命令创建一个
abuild unpack
运行 configure
还会显示你如何禁用此软件包的特定选项。例如,一个很好的例子是 "--disable-nls",它将禁用本地语言支持,因此不依赖于 gettext(libiconv、glib 等)。
Alpine 喜欢保持小巧,因此我们尝试尽可能多地禁用,而不会丢失太多功能。确切的禁用/启用选项由软件包构建者决定,但请尽量遵循 Alpine 的设计理念。
快速找出软件包的构建信息的简单方法是查看 Arch Linux(Alpine 软件包管理和构建脚本类似)或 Gentoo Linux ebuilds(Alpine 的早期版本基于 Gentoo)。
license
license 标签必须反映源代码的许可证。请检查源 tarball 中是否有 COPYING、LICENSE 或其他名称表明它包含许可信息的文件。除了许可证文件外,大多数开发者还在源代码文件中包含带有许可详细信息的标头。
如果许可证在 SPDX 许可证列表 或 SPDX 许可证例外 中,请使用 SPDX 指定的标识符。
请注意,某些许可证有应遵守的附加要求。例如,MIT
许可证有以下要求
上述版权声明和此许可声明(包括下一段)应包含在软件的所有副本或主要部分中。
这意味着我们需要包含项目附带的许可证。
需要此操作的已知许可证
MIT
ISC
如果软件包具有特殊/自定义许可证或未列为 OSI 批准,请使用标识符 "custom"。在这种情况下,我们也需要提供软件包的许可证文件。
因为我们想节省空间并且不喜欢我们的系统到处都是许可证,所以我们决定将许可证包含在 doc 子软件包中。请按照以下指南添加正确的许可证。找到源软件包内的许可证文件。将 doc 子软件包添加到 $subpackages 变量,如下所示
subpackages="$pkgname-doc"
根据许可证描述文件,将以下类似行添加到你的 package() 函数中
install -Dm644 COPYING "$pkgdir"/usr/share/licenses/$pkgname/COPYING
如果你按照这些步骤操作,abuild 将会自动将许可证添加到 package-doc apk 中。

arch
要构建的软件包架构。可以是:x86、x86_64、all 或 noarch,其中 all 表示所有架构,noarch 表示它与架构无关(例如,纯 Python 软件包)。
url
程序的网站地址。这在以后查找文档或有关软件包的其他信息时很有用。
pkgdesc
软件包功能的简短单行描述。对软件包管理系统很有用。它应以大写字母开头,并且不以句点结尾。
这是 OpenSSH 客户端软件包的 apk_info 中的一个示例
pkgdesc="Port of OpenBSD's free SSH release - client"
pkgver
提供你正在构建的软件包的发布版本号。
pkgrel
$pkgrel 版本控制是为了如果你在不更改实际 $pkgver 的情况下更改 APKBUILD 文件中的某些内容,你可以递增 pkgrel,以便 apk 工具将其检测为更新。例如,如果你忘记添加依赖项,你可以在之后添加它,并且可以 +1 pkgver,以便 apk 找到此更新并添加缺少的依赖项。当上游版本更改时,我们将 pkgrel 重置为 0。
pkgname
你正在创建的软件包的基本名称。对于 Freeswitch 1.0.6,你将使用 "freeswitch"
install
有 6 种不同的安装脚本。每个脚本都使用 $pkgname.<action> 调用,其中 <action> 是以下之一
- $pkgname.pre-install
- 此脚本在安装软件包之前执行。典型用途是软件包需要创建组和用户时。例如
#!/bin/sh addgroup -S clamav 2>/dev/null adduser -S -D -H -s /bin/false -G clamav -g clamav clamav 2>/dev/null exit 0
注意末尾的 exit 0。如果脚本以失败退出(如果用户已存在),则软件包将不会安装,并且
apk add
将以失败退出。 - $pkgname.post-install
- 此脚本在软件包安装后执行。
- $pkgname.pre-upgrade
- 与 pre-install 相同,但在升级/降级/重新安装已安装的软件包之前执行。请注意,以失败退出不会导致 apk 以失败退出,但会将软件包标记为损坏。
- $pkgname.post-upgrade
- 与 post-install 相同,但在升级/降级/重新安装已安装的软件包之后执行。
- $pkgname.pre-deinstall
- 此脚本在卸载软件包之前执行。如果脚本以失败退出,apk 将不会卸载软件包。
- $pkgname.post-deinstall
- 此脚本在软件包卸载后执行。例如,可用于恢复 busybox 链接
#!/bin/sh busybox --install -s
如果软件包具有 pre-install 和 post-install 脚本,则 APKBUILD 应定义 install 变量
... install="$pkgname.pre-install $pkgname.post-install" ...
subpackages
$subpackages 用于将正常的 "make install" 分割成单独的软件包。我们最常用的子软件包是 doc 和 dev。因为我们喜欢保持目标系统的小巧,所以我们将文档和开发文件(仅在构建软件包时需要)移动到单独的软件包中。要使用特定程序,用户只需安装基本 apk,而无需 package-doc 或 package-dev,但如果他想阅读手册,则需要安装 package-doc。
找出是否需要使用 -dev 和 -doc 的最简单方法是首先在不设置这些选项的情况下构建软件包,并等待构建完成。完成后,你应该有一个 pkg 目录,它是伪根目录。在此目录中,你将看到它将如何安装在目标系统上的 / 中的结构。
要查看是否需要 -dev 软件包,你可以运行以下 cmd
find pkg/usr/ -name '*.[acho]' -o -name '*.la'
如果这返回任何文件,则你需要包含 -dev 软件包。
要查看是否需要 -doc 软件包,你可以运行以下 cmd
find pkg/usr/share -name doc -o -name man -o -name info -o -name html -o -name sgml -o -name licenses
如果这返回任何目录,则你需要包含 -doc 软件包。
自定义子软件包
某些软件还具有非必要文件,这些文件不属于文档或开发内容。这些文件应放置在它们自己的专用子软件包中。某些软件包包含大型测试套件,这些测试套件仅在特定情况下需要,或者包含我们不希望安装的依赖项的二进制文件。为了处理这些情况,我们创建了自己的软件包/函数。在下面的 APKBUILD 中的 build() 函数之后,我们创建另一个函数
test() { mkdir -p "$subpkgdir"/usr mv "$pkgdir"/usr/package-test "$subpkgdir"/usr/ # or amove usr/package-test }
我们还需要将软件包信息添加到 $subpackages 变量
subpackages="$pkgname-doc $pkgname-dev $pkgname-test"
在我们完成构建软件包后,你应该看到另一个名为 packagename-test.apk 的 apk,其中包含我们移动到 $subpkgdir 目录的文件。
上述变量也可以在我们的自定义函数中使用。例如,如果我们想使用 perl 支持构建 test() 函数,我们将添加
depends="perl" makedepends="perl-dev"
如果我们安装基本软件包,它将不会安装 perl,但如果我们安装 package-test 软件包,它将会安装。
补丁
请确保你始终提交人类可读的补丁。创建它们的方法有
进行目录比较
diff -Nurp original_directory new_directory > filename.patch
进行文件比较
diff -up original.file new.file > filename.patch
如果补丁包含一个全新的文件,但没有 *.rej 或 *.orig 文件,则需要向 diff 添加 -N 选项,但你可能需要使用 --exclude PATTERN
添加排除项,以免意外添加文件。你可能需要在补丁文件中手动删除不需要的文件。
由于多个补丁可以修补同一个文件,它们可能会更改后续补丁所需的偏移量。为了确保我们始终以特定的方式修补,我们应该按如下方式编号补丁
10-patch1.patch 20-patch2.patch 30-patch3.patch
这样我们始终可以确保首先应用补丁 1,如果我们想在它们之间添加其他补丁,我们可以使用适当的索引(例如 11、12、21、22)。
将补丁文件的名称添加到 source 变量。如果你尚未声明自定义 prepare 函数,则无需进一步操作。否则,请确保在你的 prepare 函数中调用 default_prepare。例如
prepare() { default_prepare # do your stuff }
注意:一些较旧的软件包在 prepare 函数中包含一个 for 循环来应用补丁。这不再需要,因为补丁由 default_prepare 处理。
在 Alpine >=3.4 中,你可以定义 patch_args 来提供补丁级别。这仅在所有补丁都具有相同的补丁级别时才有效。如果有很多来自不同来源的补丁,则很可能你需要编辑它们,如下所述。
要自动修补软件包(仅在 Alpine >=3.4 中可用),如果它使用非默认 (-p1) 的补丁级别 (-pX),你需要仔细修改补丁。首先,你需要一个不会自动在 Windows 和 Unix 换行符之间转换的文本编辑器(或者,禁用此功能),以便它保留旧代码。接下来你需要做的是修改 .patch 文件中 "+++" 和 "---" 行上的路径。你可以像下面显示的那样以 a/ 和 b/ 开头路径。接下来,你需要调整路径,使相对基本路径来自 $builddir 内部。任何位于 $builddir 左侧的内容,包括 $builddir 本身,都需要从路径中删除。因此,如果 $builddir 是 /home/USER/aports/community/chromium/src/chromium-65,则需要在 "+++" 和 "---" 行上将其删除。在 chromium-65 文件夹中,你可以看到一个 src 文件夹,它有一个后代 3rdparty。如果补丁最初具有更深的补丁级别,则可能需要填写路径的缺失部分。例如,使用 find . -name "Assertions.cpp"
命令查找相对于基础文件的完整路径。
example.patch 的内容
补丁的某些部分可能已过时、完全删除(如在源代码文件中完全删除)或移动或重命名文件。你需要删除补丁的那部分,或找到代码更改的位置并重新 diff 它。
在顶部注明出处以及你最初找到它们的位置,并附上注释是一种良好的礼仪。
在 Alpine 上,不提供使用类似于 patch_opts 的全局变量排除补丁的功能。要排除补丁,你需要创建自己的自定义 prepare()。
如果你有一个包含大量补丁的整体补丁,你可以使用 filterdiff,它在 patchutils 软件包中可用。
只需执行类似的操作
makedepends="patchutils" prepare() { ... cd "$builddir" filterdiff -x '*drivers/video/logo*' "$srcdir"/original.patch > "$builddir"/modified.patch patch -p1 -i "$builddir"/modified.patch }
你需要将通配符模式放在单引号中才能使其工作。
配置选项
Alpine 具有一些我们默认设置的默认配置选项。我们使用 /usr 作为前缀,以确保所有内容都安装在 /usr 前面。如果你注意到任何内容安装在错误的目录中,请运行
./configure --help
并查看是否可以设置正确的位置。
我们在这里不讨论依赖项开关,我们已经在依赖项部分中讨论过这一点。
Make 选项
如果你在编译或使用 make/make install 安装软件包时发现奇怪的问题,你可以尝试禁用并行构建/安装。正常的 make 行是
make
要禁用并行,我们使用
make -j1
我们可以对 make install 使用相同的方法。
因为我们不想将软件包安装在我们的构建环境中,但我们想将其安装在伪根目录中,所以我们需要告诉 'make install' 使用另一个目标目录而不是 '/'。我们通过在执行 make install 时设置一个变量来做到这一点,如下所示
make DESTDIR="$pkgdir" install
请注意,某些 Makefile 不支持此变量,并且始终将软件安装在 '/' 中。为确保你不会搞砸你的构建系统,永远不要以 root 用户身份运行你的构建系统,而始终使用自定义用户并在需要时使用 doas。如果意外地 Makefile 不支持 DESTDIR 变量,它将无法安装在我们的构建系统系统目录中。
builddir
如果你使用newapkbuild创建你的 APKBUILD 文件,你必须指定解压缩的源的路径。在 prepare/build/install 过程中的各个部分,都使用了 builddir。大多数情况下,$srcdir 和 $pkgname-$pkgver 的组合将起作用。如果不起作用,请检查 /src 目录或源 tarball 以查找正确的字符串。特别是当你使用自动生成的 tarball(例如来自 github 和 gitorious)时,这需要调整。
builddir="$srcdir"/$pkgname-$pkgver
附加文件
如果你想要/需要安装上面未提及的其他文件,你可以使用以下 cmd(这是一个 conf 文件的示例)
install -Dm644 doc/$pkgname.conf "$pkgdir"/etc/$pkgname.conf
构建软件包
如果你尚未创建如上所述的校验和,你现在可以这样做
cd $pkgname abuild checksum
现在是构建我们的软件包的时候了。因为构建系统永远不应安装所有软件包,以防止链接到我们不希望它链接的软件包,所以我们递归地使用 abuild 和 -r 开关。它将从你的仓库安装所有依赖项并构建它,之后它将再次卸载所有这些依赖软件包。
abuild -r
在本地测试软件包
完成后,你的软件包将在 ~/packages
的子文件夹中找到。你可能想在你的机器上测试它,但前提是该软件包不是关键的系统软件包,例如 musl 或 apk-tools 软件包。为了避免破坏你的系统(例如使其无法使用 apk add
或恢复系统和编译器工具链),对于关键系统软件包,你应该首先在 chroot 上进行测试,然后再在实际系统中使用它。
在本地测试软件包的最佳方法是修改你的 /etc/apk/repositories
,以便它包含指向本地构建的软件包的索引 - 包含 ARCH/APKINDEX.tar.gz
的目录。例如,下面的 /etc/apk/repositories
包括 testing、community 和 main 中本地构建的软件包。要使用此示例,请将 USER
更改为你的登录名。
/etc/apk/repositories 的内容
如果你希望在不更改任何其他配置的情况下测试软件包,你可以使用 apk
的 -X, --repository
选项
doas apk add --repository /home/USER/packages/testing $pkgname
代码审查
为了使您的软件包成功通过代码审查员的审查(截至 2018 年 2 月 18 日,GitHub 上的审查员是 nmeum 和 jirutka),并可能提高接受度,需要遵循以下参考资料中列出的约定。
apkbuild-lint
: $ apkbuild-lint APKBUILD- 自定义全局变量应以下划线 (_) 为前缀。
- 精简代码,如合并命令、删除未使用的变量、删除由 abuild 自动处理的重复功能函数。
- 版本控制应正确完成。有关详细信息,请参阅 APKBUILD_Reference#pkgver。
- 许可应正确完成。删除不必要的已获 OSI 批准的许可复制。
- 非官方变量的命名约定规则,例如 _gitrev 优于 commit。
- 使用制表符而不是空格进行缩进。
- 删除显式的 return 1。(如果您正在学习,仍然可以在旧的 APKBUILD 文件中找到它们,但现在强烈不建议使用。)
- 禁用 check() 需要满足以下任一条件:(1) 在 options="!check" 旁边添加注释 (#) 说明没有测试套件/单元测试,或者 (2) 正常工作的 check() 函数。
- 必须使用显式调用 subpackages="$pkgname-doc" 来代替显式 gzip man page 压缩。
- 理想情况下,行宽应不超过 80 列
提交您的工作
在您成功构建软件包并正确遵循代码审查部分的约定和要求后,您可以将您的 APKBUILD 提交到 Alpine 的 git 存储库。
在添加新文件之前,更新您的 git 仓库
cd $aportsdir git pull
这应该将其他人所做的所有更改拉取到您的本地 git 仓库中。
当您认为准备就绪时,您可以将您的文件添加到 git
注意:当使用我们的 Gitlab 实例时,您可以为每个软件包创建 MR。请将与同一软件包相关的所有提交合并为一个 MR。
cd $aportsdir git add testing/$pkgdir (包括构建所需的任何其他文件;$pkgname.install...) git commit
对于新的 aports,请使用以下提交消息模板(不包括注释)
内容为template
或者您可以添加以下内容并 chmod +x ports/.git/hooks/prepare-commit-msg
以自动生成提交消息,而默认的 aports/.githooks/ 不会这样做
内容为aports/.git/hooks/prepare-commit-msg
现在您的更改仅在本地存储库中可用。
由于您没有 Alpine aports 存储库的推送权限,因此您需要创建一个合并请求到 Alpine 的 GitLab 实例。
或者,您也可以创建您所做更改的 diff(补丁),并将此补丁发送到 alpine-aports 邮件列表。
要创建 diff 补丁
git format-patch HEAD^
或者,如果您有 sprunge,您可以创建一个指向您的补丁的链接,以方便使用
git format-patch HEAD^ --stdout | sprunge
自动标记过时端口
考虑将您的端口添加到 Anitya,以便在上游发布新的稳定版本后,它会立即被标记为过时。