この記事は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ファイルができていれば完成です。
ね、簡単でしょ。