abuild note
https://mdb.koi.moe/ 本册子正在完善中
Alpine Linux 中文社区
Alpine Linux 官方 Wiki
- https://wiki.alpinelinux.org/wiki/Alpine_Package_Keeper
- https://wiki.alpinelinux.org/wiki/Creating_an_Alpine_package
- https://wiki.alpinelinux.org/wiki/APKBUILD_Reference
- https://wiki.alpinelinux.org/wiki/Abuild_and_Helpers
Alpine Linux 包搜索
- https://pkgs.alpinelinux.org/packages
- https://pkgs.alpinelinux.org/contents
- https://pkgs.qaq.land/
- https://alpine.pkgs.org/
APORTS 仓库
- https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/README.md
- https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/CODINGSTYLE.md
- https://gitlab.alpinelinux.org/alpine/aports/-/blob/master/COMMITSTYLE.md
其他发行版的包
本站内容使用 CC BY-NC-SA 4.0 许可证发布
构建环境
https://wiki.alpinelinux.org/wiki/Creating_an_Alpine_package
alpine-sdk
元包,包括以下三个包(安装 meta 包后,依赖会自动安装)
- abuild
- build-base
- git
build-base
也是元包,一部分是 abuild 需要的运行时依赖:
- binutils 构建相关,链接小工具
- file 检测文件类型
- patch 打 patch 用,musl 发行版需要很多 patch,还有上游的更新补丁
另一部分是大部分构建都需要的工具链:
- gcc、g++
- make
- libc-dev 约等于 musl-dev
- fortify-headers 缓冲区检查宏
所以 APKBUILD 中 makedepends 不需要再把 gcc make 写进来啦!每台打包机都默认安装了这些包
abuild
bin/abuild
根据 APKBUILD 拉取源码并更新配置文件中的校验值(构建需要)
$ abuild checksum
自动安装依赖并在构建完成后卸载依赖,自动完成整个构建过程
$ abuild -r
启动沙盒环境进行纯净构建,等同于手动创建 chroot 环境(需要安装 abuild-rootbld 包)
$ abuild rootbld
bin/newapkbuild
newapkbuild 使用模板新建(会自动创建文件夹)
$ newapkbuild -h
newapkbuild 3.12.0-r0 - generate a new APKBUILD
Usage: newapkbuild [-n PKGNAME] [-d PKGDESC] [-l LICENSE] [-u URL]
[-a | -C | -m | -p | -y | -r] [-s] [-c] [-f] [-h]
PKGNAME[-PKGVER] | SRCURL
Options:
-n Set package name to PKGNAME (only use with SRCURL)
-d Set package description to PKGDESC
-l Set package license to LICENSE, use identifiers from:
<https://spdx.org/licenses/>
-u Set package URL
-a Create autotools package (use ./configure ...)
-C Create CMake package (Assume cmake/ is there)
-m Create meson package (Assume meson.build is there)
-p Create perl package (Assume Makefile.PL is there)
-y Create python setuptools package (Assume setup.py is there)
-e Create python gpep517 package (Assume pyproject.toml is there)
-r Create rust package (Assume Cargo.toml is there)
-s Use sourceforge source URL
-c Copy a sample init.d, conf.d, and install script
-f Force even if directory already exists
-h Show this help
abuild-rootbld
$ apk add abuild-rootbld
注意事项:https://wiki.alpinelinux.org/wiki/Include:AbuildRootBld
- options 添加 net
- 上级目录下添加
.rootbld-repositories文件指定仓库或镜像(官方的 aports 自带) - 保持文件结构像
~/aports或设置环境变量APORTSDIR=$(PWD)
由于每次都是重新下载安装环境,因此可以开启安装包缓存
$ setup-apkcache
以及指定镜像源来减少等待时间。
$ mirror=http://mirrors.tuna.tsinghua.edu.cn/alpine abuild rootbld
这里的环境变量 mirror 生效是因为官方 aports 的 .rootbld-repositories 中有预留变量
lab ~/aports/community
$ bat .rootbld-repositories -p
$mirror/$version/main
$mirror/$version/community
常见问题
网络问题拉不下来构建需要的源码
abuild 内部调用的是 wget,设置 http 代理
$ https_proxy=http://localhost:7890/ abuild checksum
如何知道软件需要的依赖?
makedepends:abuild rootbld 一个一个添加 dev 包测试
depends:打包结束时 abuild 会自动识别大部分动态链接库并形成依赖关系,手动加上额外的运行时依赖,及软件间接调用的 git、bash、less 等
软件 A 依赖本地软件 B(另外一个未上传的本地包)
$ apk add --allow-untrusted xxxx.apk
当 abuild rootbld 时,添加 ~/packages/testing/ 到 ~/aports/testing/.rootbld-repositories
编译需要的 gcc 是依赖吗?
见 build-base 节
由于 musl 引起的编译错误如何解决?
应该都有人遇到过,aports 搜一搜自己也做个补丁
反复下载安装依赖耗时很久
见 abuild-rootbld 节
查看 apk 中的文件列表
$ tar -vtf file.apk
APKBUILD
Maintainer 声明
# Maintainer 需要放在 # Contributor 后。
以便在简单的更改(如只修改 pkgver 或 pkgrel) 时,能够在默认的 diff 3 行信息中看到 Maintainer 信息。
license
该标签反映上游项目的许可证,检查 COPYING、LICENSE 或源码文件的许可证标头。 开源项目的许可证应采用 SPDX License List1 或 SPDX License Exceptions2 中规定的标准标识符。
部分许可证要求在所有副本中包含版权声明、许可声明和源代码,因此需要在 package() 阶段同样 install 这些文件。
设置 subpackages="$pkgname-doc" 会自动检出相关许可文件到 -doc 子包,减小主包体积。
source
包含多个部分:
- 远程拉取的源码归档包
- 本地 patch 补丁
- 本地 openrc 配置文件(initd & confd)
但不包括 install-script
cache
远端文件会先调用 curl 或 wget3 缓存到本地 /var/cache/distfiles4
如果缓存冲突或者 rename 操作失误可以随时来此删除
环境变量参考 cURL 文档:Proxy environment variables
与 Arch 不同,如果是以打包压缩后缀 tar.gz 等结尾,后续构建会自动解压到 srcdir。
rename
远端文件以文件名为缓存,因此应避免冲突,遵守 $pkgname-$pkgver.xxx 的命名规则。
如有需要,使用重命名语法 <name>::<remote-link>:
$pkgname-$pkgver.tar.gz::https://github.com/software/software/archive/v$pkgver.tar.gz
可使用 wget --spider -S http://example.com/file.zip 查看文件名是否满足要求。
remote-link
GitHub 项目的源码归档文件下载链接参考文档5,常用 tag 和 commit
https://github.com/<user>/<repo>/archive/<commit-hash>.tar.gz
https://github.com/qaqland/display-test/archive/9e3a201a102e3e08447b75cfa0d402fac16bd496.tar.gz
https://github.com/qaqland/display-test/archive/refs/tags/v0.0.2.tar.gz
https://github.com/<user>/<repo>/archive/refs/tags/<tag-name>.tar.gz
Alpine Linux 官方的缓存可以在这里查看 https://distfiles.alpinelinux.org/distfiles/
builddir
指向 source 解压之后的文件夹(后续构建的工作目录),一般有:
$srcdir/$pkgname-$pkgver(由于是默认值 apkbuild-lint 会提示您删掉)$srcdir/v$pkgver(某些 GitHub 自动生成的 release)
可以首先使用默认值观察是否成功构建,否则前往 $srcdir 观察解压后的目录
shell
参数替换
默认值
GOCACHE=${GOCACHE:-"$srcdir/go-cache"}
如果 GOCACHE 为空或未设置,使用 "$srcdir/go-cache" 作为默认值
替换
pkgver=${_pkgver/-/.}
第一个匹配到的 - 将会被替换为 .,用于从 2.0.0-10 转换为 2.0.0.10
checkdepends="${checkdepends/binutils-gold/}"
在变量 checkdepends 的值中,将第一个匹配到的 binutils-gold 替换为空字符串(因为在第二个斜杠后面没有提供替换字符串)。即将删除 checkdepends 的值中的第一个 binutils-gold
删前缀
json=${subpkgname#libmustach-}
删去字符串前缀,如果 $subpkgname 的值是 libmustach-json-c,那么 $json 的值就是 json-c
删后缀
json=${jsondev%-dev}
删去字符串后缀,如果 $jsondev 的值是 json-c-dev,那么 $json 的值就是 json-c
Go
GOARCH 与 CARCH 不一致
一般不用设置,部分上游构建脚本(为交叉编译)需要手动指定编译架构
参考 aports/community/go/APKBUILD1
其中 CTARGET_ARCH 在交叉编译时用,一般不用考虑,直接写 CARCH 就好。
# Contributor: Sören Tempel <soeren+alpine@soeren-tempel.net>
# Contributor: Eivind Uggedal <eu@eju.no>
# Contributor: Natanael Copa <ncopa@alpinelinux.org>
# Maintainer: Sören Tempel <soeren+alpine@soeren-tempel.net>
pkgname=go
# go binaries are statically linked, security updates require rebuilds
pkgver=1.22.2
pkgrel=0
pkgdesc="Go programming language compiler"
url="https://go.dev/"
arch="all"
license="BSD-3-Clause"
depends="binutils gcc musl-dev"
makedepends="bash"
checkdepends="binutils-gold git git-daemon"
subpackages="$pkgname-doc"
source="https://go.dev/dl/go$pkgver.src.tar.gz
0001-cmd-link-prefer-musl-s-over-glibc-s-ld.so-during-dyn.patch
0002-misc-cgo-test-enable-setgid-tests-on-Alpine-Linux-ag.patch
0003-go.env-Don-t-switch-Go-toolchain-version-as-directed.patch
0004-cmd-dist-cmd-go-define-assembly-macros-handle-GOARM-.patch
tests-fchmodat-not-supported.patch
"
case "$CARCH" in
arm*|aarch64) depends="binutils-gold";;
riscv64|loongarch64)
# binutils-gold is not supported on riscv64 and loongarch64.
checkdepends="${checkdepends/binutils-gold/}"
;;
esac
# secfixes:
# 0:
# - CVE-2022-41716
# - CVE-2022-41720
# - CVE-2022-41722
# 1.22.2-r0:
# - CVE-2023-45288
# 1.22.1-r0:
# - CVE-2024-24783
# - CVE-2023-45290
# - CVE-2023-45289
# - CVE-2024-24785
# - CVE-2024-24784
# 1.21.5-r0:
# - CVE-2023-39324
# - CVE-2023-39326
# 1.21.3-r0:
# - CVE-2023-39325
# - CVE-2023-44487
# 1.21.2-r0:
# - CVE-2023-39323
# 1.21.1-r0:
# - CVE-2023-39318
# - CVE-2023-39319
# - CVE-2023-39320
# - CVE-2023-39321
# - CVE-2023-39322
# 1.20.7-r0:
# - CVE-2023-29409
# 1.20.6-r0:
# - CVE-2023-29406
# 1.20.5-r0:
# - CVE-2023-29402
# - CVE-2023-29403
# - CVE-2023-29404
# - CVE-2023-29405
# 1.20.4-r0:
# - CVE-2023-24539
# - CVE-2023-24540
# - CVE-2023-29400
# 1.20.3-r0:
# - CVE-2023-24537
# - CVE-2023-24538
# - CVE-2023-24534
# - CVE-2023-24536
# 1.20.2-r0:
# - CVE-2023-24532
# 1.20.1-r0:
# - CVE-2022-41725
# - CVE-2022-41724
# - CVE-2022-41723
# 1.19.4-r0:
# - CVE-2022-41717
# 1.19.2-r0:
# - CVE-2022-2879
# - CVE-2022-2880
# - CVE-2022-41715
# 1.19.1-r0:
# - CVE-2022-27664
# - CVE-2022-32190
# 1.18.5-r0:
# - CVE-2022-32189
# 1.18.4-r0:
# - CVE-2022-1705
# - CVE-2022-1962
# - CVE-2022-28131
# - CVE-2022-30630
# - CVE-2022-30631
# - CVE-2022-30632
# - CVE-2022-30633
# - CVE-2022-30635
# - CVE-2022-32148
# 1.18.1-r0:
# - CVE-2022-28327
# - CVE-2022-27536
# - CVE-2022-24675
# 1.17.8-r0:
# - CVE-2022-24921
# 1.17.7-r0:
# - CVE-2022-23772
# - CVE-2022-23773
# - CVE-2022-23806
# 1.17.6-r0:
# - CVE-2021-44716
# - CVE-2021-44717
# 1.17.3-r0:
# - CVE-2021-41772
# - CVE-2021-41771
# 1.17.2-r0:
# - CVE-2021-38297
# 1.17.1-r0:
# - CVE-2021-39293
# 1.17-r0:
# - CVE-2020-29509
# - CVE-2020-29511
# - CVE-2021-29923
# 1.16.7-r0:
# - CVE-2021-36221
# 1.16.6-r0:
# - CVE-2021-34558
# 1.16.5-r0:
# - CVE-2021-33195
# - CVE-2021-33196
# - CVE-2021-33197
# - CVE-2021-33198
# 1.16.4-r0:
# - CVE-2021-31525
# 1.16.2-r0:
# - CVE-2021-27918
# - CVE-2021-27919
# 1.15.7-r0:
# - CVE-2021-3114
# - CVE-2021-3115
# 1.15.5-r0:
# - CVE-2020-28362
# - CVE-2020-28366
# - CVE-2020-28367
# 1.15.2-r0:
# - CVE-2020-24553
# 1.15-r0:
# - CVE-2020-16845
# 1.14.5-r0:
# - CVE-2020-15586
# 1.13.7-r0:
# - CVE-2020-7919
# 1.13.2-r0:
# - CVE-2019-17596
# 1.13.1-r0:
# - CVE-2019-16276
# 1.12.8-r0:
# - CVE-2019-9512
# - CVE-2019-9514
# - CVE-2019-14809
# 1.11.5-r0:
# - CVE-2019-6486
# 1.9.4-r0:
# - CVE-2018-6574
if [ "$CBUILD" = "$CTARGET" ]; then
makedepends="go-bootstrap $makedepends"
provides="go-bootstrap=$pkgver-r$pkgrel"
else
pkgname="go-bootstrap"
makedepends="go $makedepends"
# Go expect host linker instead of the cross-compiler
export CC_FOR_TARGET="$CC"
export CC="${HOSTLD:-gcc}"
export CXX="${HOSTLD:-g++}"
export LD="${HOSTLD:-ld}"
fi
case "$CTARGET_ARCH" in
aarch64) export GOARCH="arm64" ;;
armel) export GOARCH="arm" GOARM=5 ;;
armhf) export GOARCH="arm" GOARM=6 ;;
armv7) export GOARCH="arm" GOARM=7 ;;
s390x) export GOARCH="s390x" ;;
x86) export GOARCH="386" ;;
x86_64) export GOARCH="amd64" ;;
ppc64) export GOARCH="ppc64" ;;
ppc64le) export GOARCH="ppc64le" ;;
riscv64) export GOARCH="riscv64" ;;
loongarch64) export GOARCH="loong64" ;;
*) export GOARCH="unsupported";;
esac
compile go itself as a PIE on supported arches.
case "$CARCH" in
x86_64|s390x|aarch64) export GO_LDFLAGS=-buildmode=pie ;;
esac
prepare() {
default_prepare
# The GitLab CI builds aports in a container. On ppc64le, ASLR
# needs to be disabled in order to have the following test case
# pass. However, the container doesn't have permissions to
# disable ASLR, hence we just disable this test for now.
#
# See https://github.com/golang/go/issues/49066#issuecomment-1252948861
if [ "$CTARGET_ARCH" = "ppc64le" ]; then
rm test/fixedbugs/bug513.go
fi
}
builddir="$srcdir"/go
build() {
cd "$builddir/src"
export GOOS="linux"
export GOPATH="$srcdir"
export GOROOT="$builddir"
export GOBIN="$GOROOT"/bin
export GOROOT_FINAL=/usr/lib/go
local p; for p in /usr/lib/go-bootstrap /usr/lib/go-linux-$GOARCH-bootstrap /usr/lib/go; do
if [ -d "$p" ]; then
export GOROOT_BOOTSTRAP="$p"
break
fi
done
./make.bash -v
# copied from bootstrap.bash to fixup cross-built bootstrap go
if [ "$CBUILD" != "$CTARGET" ]; then
local gohostos="$(../bin/go env GOHOSTOS)"
local gohostarch="$(../bin/go env GOHOSTARCH)"
mv ../bin/*_*/* ../bin
rmdir ../bin/*_*
rm -rf "../pkg/${gohostos}_$gohostarch"* "../pkg/tool/${gohostos}_$gohostarch"*
rm -rf ../pkg/bootstrap ../pkg/obj
fi
}
check() {
cd "$builddir/src"
if [ "$CTARGET_ARCH" = "armhf" ]; then
export GO_TEST_TIMEOUT_SCALE=2
fi
# Test suite does not pass with ccache, thus remove it form $PATH.
export PATH="$(echo "$PATH" | sed 's|/usr/lib/ccache/bin:||g')"
PATH="$builddir/bin:$PATH" ./run.bash -no-rebuild
}
package() {
mkdir -p "$pkgdir"/usr/bin "$pkgdir"/usr/lib/go/bin "$pkgdir"/usr/share/doc/go
for binary in go gofmt; do
install -Dm755 bin/"$binary" "$pkgdir"/usr/lib/go/bin/"$binary"
ln -s /usr/lib/go/bin/"$binary" "$pkgdir"/usr/bin/
done
cp -a misc pkg src lib "$pkgdir"/usr/lib/go
cp -r doc "$pkgdir"/usr/share/doc/go
rm -rf "$pkgdir"/usr/lib/go/pkg/obj
rm -rf "$pkgdir"/usr/lib/go/pkg/bootstrap
rm -f "$pkgdir"/usr/lib/go/pkg/tool/*/api
# Install go.env, see https://go.dev/doc/toolchain#GOTOOLCHAIN.
install -Dm644 "$builddir"/go.env "$pkgdir"/usr/lib/go/go.env
install -Dm644 VERSION "$pkgdir/usr/lib/go/VERSION"
# Remove tests from /usr/lib/go/src to reduce package size,
# these should not be needed at run-time by any program.
find "$pkgdir"/usr/lib/go/src \( -type f -a -name "*_test.go" \) \
-exec rm -rf \{\} \+
find "$pkgdir"/usr/lib/go/src \( -type d -a -name "testdata" \) \
-exec rm -rf \{\} \+
# Remove rc (plan 9) and bat scripts (windows) to reduce package
# size further. The bash scripts are actually needed at run-time.
#
# See: https://gitlab.alpinelinux.org/alpine/aports/issues/11091
find "$pkgdir"/usr/lib/go/src -type f -a \( -name "*.rc" -o -name "*.bat" \) \
-exec rm -rf \{\} \+
}
sha512sums="
f2491d2b5d4ef2dd86ca7820503a2534cd1860822049dc01a6cb40b556a0812cfc4196fa83173765816060253ac949f4165b0fb4b2bed5d45e30d03bb69e434d go1.22.2.src.tar.gz
34dbe032c5f08dd8a7aad36fc4d54e746a876fdadc25466888a2f04f5a9d53103190ebd68d3cf978d3a041976185e30ffb25611fb577d031c159810d2d4c7c41 0001-cmd-link-prefer-musl-s-over-glibc-s-ld.so-during-dyn.patch
89ab4fbb2901d3907e9661dce877ee45b4a4ee07b964dca341235420ee08764f49aed5da1596d28c649e349af19ea49c03ab6f2c2ad7588a4cf950a619c10e9b 0002-misc-cgo-test-enable-setgid-tests-on-Alpine-Linux-ag.patch
8061e4ef9d7dd31804bd8d98c95afa5dd82567940b3436f45f874e0419e324b49713d8a814df04617e575ec3c6155199c4661352ea8aef63ead81ca3020f3dc4 0003-go.env-Don-t-switch-Go-toolchain-version-as-directed.patch
a69a836364be8857f153b606769a155d89fdbbac39af6fbbc3cd923e95a15805f7497d6fdce6176a18a9ccee867946a03b809d8a4a32765dd20086115f179929 0004-cmd-dist-cmd-go-define-assembly-macros-handle-GOARM-.patch
33ecefca77fa0af52a3b2b66a76977af27a88c8dddb89f03e0a5ae6794b9aac53a62d7be33020b49022e9a89d4cdfa383038ee10e160eb94548b2430bf3cfb5e tests-fchmodat-not-supported.patch
"
避免 Go 缓存污染外部环境
WIP2
Python
venv
In check() part, setup venv and use python from there:
python3 -m venv --clear --system-site-packages .testenv
.testenv/bin/python3 -m installer xxx.whl
.testenv/bin/python3 -m pytest
PATH
Export $PATH if needed (some test call binrary)
export PATH="$builddir"/.testenv/bin:$PATH
Be careful that all runpart check() and package() are in the same process
sharing same environment.
pip
By default, pip install source files within "another" isolation,
but we usually want to use packages from system and build():
.testenv/bin/python3 -m pip install --no-build-isolation --no-index xxx