背景
最近由于工作原因需要使用WiredTiger特定版本去修复数据,查看了各个Docker镜像发现支持的版本不一样,比如Ubuntu支持3.2.1,Alpine Linux3.16支持到3.0.0。原本想使用Alpine Linux编译下3.2.1版本,发现编译通过不了,索性不整了,把官方的3.0.0的编译脚本学习下,借机会学下Apline Linux平台的包编译。
Alpine Linux Package
平台使用Ubuntu平台,包格式是deb包,Alpine Linux平台使用apk格式的package。
官方维护有官方的仓库,但是每个版本的pacakge有变化,比如Alpine Linux v3.16维护了libexecinfo-dev,但是后面的版本没有了,wiredtiger在v3.9后就不维护了。
每个版本的apk包的编译脚本在官方的aports中维护,里面包括不同类型的仓库,包括main、community、testing。
编译apk包使用abuild命令,需要在Alpine中安装alpine-sdk,她依赖abuild、build-base、git。
本文主要利用wiredtiger官方脚本在v3.16中编译成apk包。
Package Build
包编译最重要的文件是APKBUILD,类似shell脚本,里面包含了编译相关的各种信息,官方维护的aport里面有所有软件的APKBUILD。APKBUILD里面的变量解释本文不介绍,遇到了可以查看官方文档。下面看下wiredtiger的官方脚本。
bash
# Maintainer: Philipp Andronov <filipp.andronov@gmail.com>
# Contributor: Marc Vertes <mvertes@free.fr>
pkgname=wiredtiger
mongodb_version=3.6.3
pkgver=3.0.0.$mongodb_version
pkgrel=0
pkgdesc="High performance, scalable, production quality, NoSQL, Open Source extensible platform for data management"
url="http://www.wiredtiger.com"
arch="x86_64"
license="(GPL-2.0 or GPL-3.0) and MIT and BSD"
depends=""
depends_dev="autoconf automake libtool linux-headers"
makedepends="$depends_dev lz4-dev zlib-dev snappy-dev libexecinfo-dev"
options=""
subpackages="$pkgname-doc $pkgname-dev $pkgname-libs"
install=""
source="$pkgname-$pkgver-mongodb-$mongodb_version.tar.gz::https://github.com/wiredtiger/wiredtiger/archive/mongodb-$mongodb_version.tar.gz
makemake-remove-libtool-version.patch
10-fix-code-generator.patch
"
_builddir="$srcdir"/$pkgname-mongodb-$mongodb_version
prepare() {
local i
cd "$_builddir"
for i in $source; do
case $i in
*.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;;
esac
done
sh autogen.sh || return 1
}
build() {
cd "$_builddir"
./configure --prefix=/usr \
--disable-static \
--enable-verbose \
--enable-lz4 \
--with-builtins=zlib,snappy \
|| return 1
make || return 1
}
package() {
cd "$_builddir"
make DESTDIR="$pkgdir" install
install -Dm644 LICENSE "$pkgdir"/usr/share/licenses/$pkgname/LICENSE
}
sha512sums="051342439eea7bfb65dddbd42eab646bc007e9768d8bb82aeab6245cefcc99f9c3acae66a4caf60304256fd2cd55ceeba8b09b91743756b36ec6f367281070ca wiredtiger-3.0.0.3.6.3-mongodb-3.6.3.tar.gz
9eb56a81cbf0b8c695ab86d5c6aa319aee8e6ffc4d4ac94c5ecb17a639cab352f83fdf15db467d3f2961cd05fd00c2b96c3cc357daa32972dd07fb3dfa95852f makemake-remove-libtool-version.patch
a24360c18a8dd677a1942fc66ecdfdb8bc514af6de3e19be822293fdc83c051c43f3270f91eaa4524f30b5bc82c6ecad5162ce5b3f5ff470bab4e1a5d9eb79ec 10-fix-code-generator.patch"
上述是官方的WiredTiger
的脚本,脚本类似shell脚本,里面的各种variable名字已经说明了,可以参考官方文档。主要是全局环境变量和lifecycle自定义函数,其中有两个注意点:
- patch文件。apk编译支持patch文件,使用
git diff
生成,比如
bash
git diff dist/s_typedef > fix-code-generator-3_2_1.patch
- 最后的
sha512sums
是可以官方命令根据source
参数生成
bash
# 需要进入有APKBUILD文件的文件夹执行
abuild checksum
当APKBUILD和patch文件完成后,在当前目录中执行
bash
REPODIST=~/packages/ abuild -r
Docker环境下编译
有了大致了解后,因为没有Alpine Linux环境,可以使用Docker环境,方便快捷,关键还不污染宿主机环境。 在实验中,中间经过了大量的测试,下面Dockerfile是最终脚本。
bash
# Dockerfile
# docker build --progress plain -t wiredtiger-multistep:0.0.2 . 2>&1 | tee build.log
FROM alpine:3.16 as builder
COPY APKBUILD 10-fix-code-generator.patch makemake-remove-libtool-version.patch /home/packager/wiredgiter/main/wiredtiger/
RUN set -x;\
sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories; \
apk update; \
apk add --update --no-cache --no-progress alpine-sdk build-base sudo; \
adduser -D packager; \
addgroup packager abuild; \
echo 'packager ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/packager; \
chown -R packager:packager /home/packager
USER packager
WORKDIR /home/packager/wiredgiter/main/wiredtiger/
RUN set -x; \
abuild-keygen -n --append --install ; \
REPODEST=~/packages/3.16 abuild -r
FROM alpine:3.16 as prod
# 注意apk的位置
COPY --from=builder /home/packager/.abuild/*.pub /etc/apk/keys/
COPY --from=builder /home/packager/packages/3.16/main/x86_64/wiredtiger*.apk /tmp/
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories; \
apk add /tmp/wiredtiger-libs-3.0.0.3.6.3-r0.apk; \
apk add /tmp/wiredtiger-3.0.0.3.6.3-r0.apk
注意
Alpine Linux编译package的最终地址整了半天,最终地址为:$REPODEST/$repo
,其中REPODEST默认为$HOME/packages,这个默认值在/etc/abuild.conf文件夹中设置
bash
repo=${startdir%/*}
repo=${repo##*/}
其中startdir
为APKBUILD
所在目录,所以repo实际上是APKBUILD上一级文件夹名称,比如APKBUILD位于/home/packager/wiredtiger/main/wiredtiger
中,那repo就是main
。
所以默认情况下地址为:/home/packager/packages/main/
,最终还会填上平台文件夹。
附录
abuild编译时中默认环境变量
bash
startdir="APKBUILD脚本所在的文件夹"
srcdir=${srcdir:-"$startdir/src"}
pkgbasedir=${pkgbasedir:-"$startdir/pkg"}
repo=${startdir%/*}
repo=${repo##*/}
builddir=${builddir:-"$srcdir/$pkgname-$pkgver"}
默认abuild.conf文件
bash
export CFLAGS="-Os -fomit-frame-pointer"
export CXXFLAGS="$CFLAGS"
export CPPFLAGS="$CFLAGS"
export LDFLAGS="-Wl,--as-needed,-O1,--sort-common"
export GOFLAGS="-buildmode=pie"
# Do note that these should work with at least GDC and LDC
export DFLAGS="-Os"
export JOBS=$(nproc)
export MAKEFLAGS=-j$JOBS
export SAMUFLAGS=-j$JOBS
export CARGO_BUILD_JOBS=$JOBS
# remove line below to disable colors
USE_COLORS=1
# uncomment line below to enable ccache support.
#USE_CCACHE=1
SRCDEST=/var/cache/distfiles
# uncomment line below to store built packages in other location
# The package will be stored as $REPODEST/$repo/$pkgname-$pkgver-r$pkgrel.apk
# where $repo is the name of the parent directory of $startdir.
REPODEST=$HOME/packages/
# PACKAGER and MAINTAINER are used by newapkbuild when creating new aports for
# the APKBUILD's "Contributor:" and "Maintainer:" comments, respectively.
#PACKAGER="Your Name <your@email.address>"
#MAINTAINER="$PACKAGER"
# what to clean up after a successful build
CLEANUP="srcdir bldroot pkgdir deps"
# what to cleanup after a failed build
ERROR_CLEANUP="bldroot deps"
参考资料
替换国内源
查看Alpine Linux软件
wiredtiger aports APKBUILD脚本
APKBUILD Reference
Alpine编译apk安装包
Alpine Linux支持的平台
本地搭建第三方Alpine repo
create an Alpine package
How to Build an Alpine Linux Package
Building / consuming alpine Linux packages inside containers and images
BUILD ALPINE PACKAGES IN A TEMPORARY CONTAINER
WiredTiger document
all about APK build