Alpine Linuxの自前パッケージをビルドする方法
この記事はRecruit Advent Calendar 2021 - Adventarの24日目(12/24)のエントリーです。 adventar.org
1. Alpine Linuxとは?
Alpine LinuxはDockerイメージ作成でも良く使われるLinuxディストリビューションの一つで、組み込み用途で使われていたbusyboxを標準で利用し、豪華な構文を持ったbashではなくシンプルなash、機能の多いglibcではなく簡素なmusl-libcを採用していて、トータルのバイナリサイズがとても小さいという特徴があります。Alpine Linuxでは、apkコマンド(Debian系だとapt、RedHat系だとyumに相当)を利用してパッケージインストールができるのですが、この記事では自前のapkパッケージをビルドする方法について解説します。
2. ユーザの作成
Alpine Linux上でパッケージをビルドするユーザtakesakoを作成し(このユーザ名は自分の名前に変えてください)、abuildグループに所属させます。この作業はrootで行います。
adduser takesako addgroup takesako abuild
標準ではsudoパッケージがインストールされていないので、apkコマンドを利用してパッケージをインストールし、visudoコマンドで/etc/sudoersを編集してwheelグループに権限を付与します。
apk add sudo visudo addgroup takesako wheel
もしもあなたが(emacs派、nano派など)宗教上の理由でvisudoコマンドを使いたくない場合は、以下のように設定しても大丈夫です。
echo "takesako ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/takesako chmod 440 /etc/sudoers.d/takesako
ちなみに、Alpine Linuxでは設定が豊富なsudoではなく、OpenBSDで開発が進められていたdoasコマンドも利用できますので、そちらを使うのも良いでしょう。
3. alpine-sdkのインストール
apkパッケージのビルドに必要なalpine-sdkパッケージをインストールします。
apk add alpine-sdk
これは中身のないメタパッケージとなっており、依存関係のあるパッケージ群が自動でインストールされます。
alpine-sdkのAPKBUILDファイル(~/aports/main/alpine-sdk/APKBUILD
)は以下の通りです。
# Maintainer: Natanael Copa <ncopa@alpinelinux.org> pkgname=alpine-sdk pkgver=1.0 pkgrel=1 url="https://git.alpinelinux.org/" pkgdesc="Alpine Software Development Kit meta package" depends="abuild build-base git" arch="noarch" license="GPL-2.0" build() { # meta package return 0 } package() { mkdir -p "$pkgdir" }
APKBUILDのリファレンスはhttps://wiki.alpinelinux.org/wiki/APKBUILD_Referenceにありますが、
depends="abuild build-base git"
という個所で必要な他のパッケージの依存関係を指定していて、apk addしたときに依存関係のあるabuildパッケージと、build-baseパッケージと、gitパッケージが足りなければ自動でインストールされます。
4. 自分の名前とメールアドレスの設定
パッケージをビルドするユーザでログインして、git configで自分の名前とメールアドレスを設定します。
login takesako git config --global user.name "Your Full Name" git config --global user.email "your@email.address"
他に/etc/abuild.confファイルにも自分の名前とメールアドレスを記載する場所があるので、
sudo vi /etc/abuild.conf
コマンドを実行して、以下を書き換えます。
PACKAGER="Your Full Name <your@email.address>" MAINTAINER="$PACKAGER"
5. キャッシュディレクトリの権限追加
ダウンロードしたソースコードを置くキャッシュディレクトリとして/var/cache/distfiles
があるので、abuildグループ権限で書き込みができるようにしておくと便利です。
sudo mkdir -p /var/cache/distfiles sudo chgrp abuild /var/cache/distfiles sudo chmod g+w /var/cache/distfiles
6. 公開鍵と秘密鍵の生成
abuild-keygenというスクリプトが用意されているので、-a(--append)と-i(--install)オプションを指定して公開鍵と秘密鍵を生成します。
abuild-keygen -a -i
鍵の保存場所を聞かれますが、そのままエンターキーを押してデフォルトの場所のままにしておいても良いでしょう。
>>> Generating public/private rsa key pair for abuild Enter file in which to save the key [/home/takesako/.abuild/your@email.address-1a2b3c4d.rsa]: Generating RSA private key, 2048 bit long modulus (2 primes) ................+++++ .........................+++++ e is 65537 (0x010001) writing RSA key >>> Installing /home/takesako/.abuild/your@email.address-1a2b3c4d.rsa.pub to /etc/apk/keys... >>> >>> Please remember to make a safe backup of your private key: >>> /home/takesako/.abuild/your@email.address-1a2b3c4d.rsa >>>
ここでビルドしたapkファイルを他のマシン上でインストールするには、ここで生成した公開鍵の.rsa.pubファイルを/etc/apk/keys/
以下に置く必要があります。(※.pubのない.rsaファイルは秘密鍵です)
7. APKBUILDの雛形作成
APKBUILDファイルの雛形作成には、newapkbuildコマンドを利用すると便利です。
newapkbuild 3.7.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 package (Assume setup.py is there) -r Crate 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
たとえば、何もオプションを指定せずに、
newapkbuild aaa
コマンドを実行すると、aaa/APKBUILD
に以下のファイルが生成されます。
# Contributor: Yoshinori Takesako <takesako@namazu.org> # Maintainer: Yoshinori Takesako <takesako@namazu.org> pkgname=aaa pkgver= pkgrel=0 pkgdesc="" url="" arch="all" license="" depends="" makedepends="" install="" subpackages="$pkgname-dev $pkgname-doc" source="" builddir="$srcdir/" build() { # Replace with proper build command(s) : } check() { # Replace with proper check command(s) : } package() { # Replace with proper package command(s) : }
これにビルドに必要な情報を埋めていけば、APKBUILDファイルの完成です。
8. 実用例:cycfx2progパッケージの作成
実用例として、cycfx2progパッケージを作成してみます。cycfx2progはEZ-USBなどのFX2系組み込みデバイスのファームウェア書き込みに利用するコマンドです。
mkdir -p test/cycfx2prog cd test/cycfx2prog vi APKBUILD
作成するAPKBUILDファイルは以下の通りです。
# Contributor: Yoshinori Takesako <takesako@namazu.org> # Maintainer: Yoshinori Takesako <takesako@namazu.org> pkgname=cycfx2prog pkgver=0.47 pkgrel=0 pkgdesc="download 8051 program into the FX2 board" url="https://www.triplespark.net/elec/periph/USB-FX2/software/" arch="all" license="GPL2" depends="libusb-compat" makedepends="libusb-compat-dev" install="" subpackages="" source="https://www.triplespark.net/elec/periph/USB-FX2/software/$pkgname-$pkgver.tar.gz Makefile.patch " builddir="$srcdir/$pkgname-$pkgver" build() { cd "$builddir" make } check() { return 0 } package() { cd "$builddir" install -D -m 755 cycfx2prog "$pkgdir"/usr/bin/cycfx2prog }
あと、Makefile.patchファイルも以下で作っておきます。
cat<<EOF>Makefile.patch --- cycfx2prog-0.47/Makefile +++ cycfx2prog-0.47-new/Makefile @@ -9,7 +9,7 @@ # NOTE: Also add sources to the "dist:" target! cycfx2prog: cycfx2prog.o cycfx2dev.o - $(CC) $(LDFLAGS) cycfx2prog.o cycfx2dev.o -o cycfx2prog + $(CC) cycfx2prog.o cycfx2dev.o -o cycfx2prog $(LDFLAGS) EOF
これは$(LDFLAGS)を後ろに書かないと、libusbのリンクに失敗する問題を修正しています。
9. ソースコードのダウンロードとchecksumの更新
abuild checksumコマンドを実行して、ソースコードのダウンロードとchecksumの更新を行います。
abuild checksum
実行すると、以下のようにダウンロード画面が表示されます。
>>> cycfx2prog: Fetching https://www.triplespark.net/elec/periph/USB-FX2/software/cycfx2prog-0.47.tar.gz % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 8768 100 8768 0 0 5299 0 0:00:01 0:00:01 --:--:-- 5301 >>> cycfx2prog: Updating the sha512sums in APKBUILD...
ダウンロード終了後、sha512ハッシュ値が計算され、APKBUILDファイルにchecksumの値が書き込まれます。
sha512sums="089895f0c4b45012f9f9fc607a30c2e2897f360d270973354fa739cc456d2728080733461f6a3681422049599947461c05e5d9e7e598fc3c9fd6d5a7d89e346c cycfx2prog-0.47.tar.gz ac62c7b1a13d144f5ceacc425a6c1487bf390273d4cf33cfe1c3ee5498d47b3c80c72ab5b8f189171d294da3bb001b42b1978d46937cf59578b35772c724d679 Makefile.patch"
10. パッケージビルドの実行
abuild -rコマンドを実行して、パッケージをビルドします。
alpine:~/cycfx2prog$ abuild -r >>> cycfx2prog: Building test/cycfx2prog 0.47-r0 (using abuild 3.7.0-r0) started Fri, 24 Dec 2021 13:52:20 +0000 >>> cycfx2prog: Checking sanity of /home/test/cycfx2prog/APKBUILD... >>> cycfx2prog: Analyzing dependencies... >>> cycfx2prog: Installing for build: build-base libusb-compat libusb-compat-dev (1/5) Installing libusb (1.0.24-r1) (2/5) Installing libusb-compat (0.1.5-r4) (3/5) Installing libusb-dev (1.0.24-r1) (4/5) Installing libusb-compat-dev (0.1.5-r4) (5/5) Installing .makedepends-cycfx2prog (20211224.135220) Executing busybox-1.32.1-r6.trigger OK: 276 MiB in 103 packages >>> cycfx2prog: Cleaning up srcdir >>> cycfx2prog: Cleaning up pkgdir >>> cycfx2prog: Fetching https://www.triplespark.net/elec/periph/USB-FX2/software/cycfx2prog-0.47.tar.gz >>> cycfx2prog: Fetching https://www.triplespark.net/elec/periph/USB-FX2/software/cycfx2prog-0.47.tar.gz >>> cycfx2prog: Checking sha512sums... cycfx2prog-0.47.tar.gz: OK Makefile.patch: OK >>> cycfx2prog: Unpacking /var/cache/distfiles/cycfx2prog-0.47.tar.gz... >>> cycfx2prog: Makefile.patch patching file Makefile Hunk #1 succeeded at 9 with fuzz 2. gcc -pipe -c -O2 -fno-rtti -fno-exceptions -DCYCFX2PROG_VERSION=\"0.47\" -W -Wall -Wformat cycfx2prog.cc gcc -pipe -c -O2 -fno-rtti -fno-exceptions -DCYCFX2PROG_VERSION=\"0.47\" -W -Wall -Wformat cycfx2dev.cc In file included from cycfx2dev.cc:18: cycfx2dev.cc: In member function 'int CypressFX2Device::_ProgramIHexLine(const char*, const char*, int)': cycfx2dev.cc:393:16: warning: comparison of unsigned expression in '>= 0' is always true [-Wtype-limits] 393 | assert(nbytes>=0 && nbytes<256); | ~~~~~~^~~ gcc -pipe cycfx2prog.o cycfx2dev.o -o cycfx2prog -lusb >>> cycfx2prog: Entering fakeroot... >>> cycfx2prog*: Running postcheck for cycfx2prog >>> cycfx2prog*: Preparing package cycfx2prog... >>> cycfx2prog*: Stripping binaries fatal: not a git repository (or any of the parent directories): .git fatal: not a git repository (or any of the parent directories): .git >>> cycfx2prog*: Scanning shared objects >>> cycfx2prog*: Tracing dependencies... libusb-compat so:libc.musl-x86.so.1 so:libusb-0.1.so.4 >>> cycfx2prog*: Package size: 48.0 KB >>> cycfx2prog*: Compressing data... >>> cycfx2prog*: Create checksum... >>> cycfx2prog*: Create cycfx2prog-0.47-r0.apk >>> cycfx2prog: Build complete at Fri, 24 Dec 2021 13:52:21 +0000 elapsed time 0h 0m 1s >>> cycfx2prog: Cleaning up srcdir >>> cycfx2prog: Cleaning up pkgdir >>> cycfx2prog: Uninstalling dependencies... (1/5) Purging .makedepends-cycfx2prog (20211224.135220) (2/5) Purging libusb-compat-dev (0.1.5-r4) (3/5) Purging libusb-compat (0.1.5-r4) (4/5) Purging libusb-dev (1.0.24-r1) (5/5) Purging libusb (1.0.24-r1) Executing busybox-1.32.1-r6.trigger OK: 275 MiB in 98 packages >>> cycfx2prog: Updating the test/x86 repository index... >>> cycfx2prog: Signing the index...
エラーがなければ、~/packages/test/x86/
ディレクトリに以下のファイルが書き込まれます。
ls -l ~/packages/test/x86/ total 20 -rw-r--r-- 1 test test 754 Dec 24 14:09 APKINDEX.tar.gz -rw-r--r-- 1 test test 13795 Dec 24 14:09 cycfx2prog-0.47-r0.apk
ここでcycfx2prog-0.47-r0.apk
ファイルができていれば完成です。
ね、簡単でしょ。