はじめに
PowerBook G4にGentoo Linuxを入れていたのですが、あまりにもemergeに時間がかかるので、パッケージのクロスビルドを行おうと考えました。distccを使っていたのですが、ホストの性能がダメダメなのか、そんなに早くないので変えることにしました。
環境
とりあえず、クロスビルド用のGentoo Linuxを用意します。WSLにサックと導入しました。Systemd版です。ここらへんのページを参考にしました。めんどくさいのでユーザはrootのままです。
pong.ursm.jp「Gentooはどんどん簡単になっている」
Gentoo Linux Wiki「WSL内でのGentoo」
名前解決が何故かできなかったのですが、rm /etc/resolv.conf
ln -s /mnt/wsl/resolv.conf /etc/resolv.conf
で、resolv.confをwslが生成したものに変え、systemctl stop systemd-resolved.service
systemctl disable systemd-resolved.service
でststemd-resolvedを停止したところ名前解決ができるようになりました。
なんか、gpg鍵も取ってきてくれなかったのでgetuto --auto
で取得しました。
クロスビルド環境の構築
参考にしたサイト
Gentoo Linux Wiki「Cross build environment」
Gentoo Linux Wiki「Embedded Handbook/General/Compiling with QEMU user chroot」
Gentoo Linux Wiki「crossdev」
1. crossdev、eselectのインストールemerge -av crossdev eselect-repository
2. Crossdev overlayの作成eselect repository create crossdev
3. toolchainのインストールと設定crossdev --stable --target powerpc-unknown-linux-gnu
stableオプションを付けないと~なバージョンをインストールされてしまい、母艦のglicやgccとバージョンが合わなくなってしまったりします。
/usr以下に生成されますPORTAGE_CONFIGROOT=/usr/powerpc-unknown-linux-gnu eselect profile list
でプロファイルの一覧を表示し、PORTAGE_CONFIGROOT=/usr/
powerpc-unknown-linux-gnu
eselect profile set default/linux/ppc/23.0/systemd
でプロファイルの設定を行います。母艦のamd64用のプロファイルしか出てこないことがありますが、適当に、ln -s /var/db/repos/gentoo/profiles/default/linux/ppc/23.0/systemd /usr/powerpc-unknown-linux-gnu/etc/portage/make.profile
とかでシンボリックリンクを作成したあとにもう一度実行すれば正しいものが適用されます。
4. make.confの設定
一応バックアップを取ります。cp /usr/powerpc-unknown-linux-gnu/etc/portage/make.conf /usr/powerpc-unknown-linux-gnu/etc/portage/make.back
PowerBook G4の方のmake.confが以下のような感じなので、
COMMON_FLAGS="-mcpu=7450 -O2 -maltivec -mabi=altivec -pipe"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
FCFLAGS="${COMMON_FLAGS}"
FFLAGS="${COMMON_FLAGS}"
CHOST="powerpc-unknown-linux-gnu
ACCEPT_LICENSE="*"
MAKEOPTS="-j56"
NINJAOPTS="-j56"
CPU_FLAGS_PPC="altivec"
ACCEPT_KEYWORDS="ppc"
USE="X opengl gtk systemd dbus acpi mtp networkmanager bluetooth alsa pulseaudio cups fcitx5"
INPUT_DEVICES="libinput synaptics"
VIDEO_CARDS="ati radeon r300"
GRUB_PLATFORMS="ieee1275"
これをいい感じに書き換えてvim /usr/powerpc-unknown-linux-gnu/etc/portage/make.conf
の中身は、
CHOST=powerpc-unknown-linux-gnu
CBUILD=x86_64-pc-linux-gnu
ROOT=/usr/${CHOST}/
ACCEPT_KEYWORDS="ppc"
ACCEPT_LICENSE="*"
USE="pam X opengl gtk systemd dbus acpi mtp networkmanager alsa pulseaudio cups fcitx5"
COMMON_FLAGS="-mcpu=7450 -O2 -maltivec -mabi=altivec -pipe"
CFLAGS="${COMMON_FLAGS}"
CXXFLAGS="${COMMON_FLAGS}"
FCFLAGS="${COMMON_FLAGS}"
FFLAGS="${COMMON_FLAGS}"
FEATURES="-collision-protect sandbox buildpkg noman noinfo nodoc -pid-sandbox -network-sandbox"
# Be sure we dont overwrite pkgs from another repo..
PKGDIR=${ROOT}var/cache/binpkgs/
PORTAGE_TMPDIR=${ROOT}tmp/
MAKEOPTS="-j56"
NINJAOPTS="-j56"
CPU_FLAGS_PPC="altivec"
VIDEO_CARDS="ati radeon r300"
としました。
5. ビルドのテスト
とりあえず、htopをビルドしてみます。powerpc-unknown-linux-gnu-emerge -av htop
完了すると、/usr/powerpc-unknown-linux-gnu/var/cache/binpkgs/sys-process/htop/
にgpkgが生成されます。
ここまででもgccとg++だけを使うパッケージならインストール・ビルドできます。しかしながら、他のビルドツールを使用したりインストール段階でpowerpc用のバイナリを使用する物の場合、アーキテクチャが違うので実行できません。そのためQEMUを使用したChrootが必要になってきます。
6. ステージの適用
インストール時と同じ用にStage3を適用させます。cd /usr/powerpc-unknown-linux-gnu
wget ステージのURL
tar -xJpf stage3-*.tar.xz --xattrs-include='.*' --exclude=dev --skip-old-files
で展開します。
7. QEMUのインストールvim /etc/portage/package.use/qemu
に
app-emulation/qemu QEMU_SOFTMMU_TARGETS: ppc
app-emulation/qemu QEMU_USER_TARGETS: ppc
app-emulation/qemu static-user static-libs
とインストールするシミュレーションするアーキテクチャを指定します。そしてインストールemerge -a --buildpkg --oneshot app-emulation/qemu
多分USEの変更を求めれるので適当にdispatch-conf
します。
crossbuild環境にインストールcd /usr/powerpc-unknown-linux-gnu && ROOT=$PWD/ emerge --ask --usepkgonly --oneshot --nodeps qemu
8. QEMUの設定
ラッパーを使ってQEMUをPowerPC G4用の設定にします。これをせずに、/etc/binfmt.d/qemu.confを使用すると
qemu: uncaught target signal 4 (Illegal instruction) – core dumped
Illegal instruction (core dumped)
とか言われてほとんど動きません。また、chroot外で動作させようとするとライブラリの場所が異なるためライブラリが見つからずエラーになります。これらを防ぐためにラッパーを書きます。cd
vim qemu-ppc-g4-wrapper_chroot.c
に
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv, char **envp) {
char *newargv[argc + 3];
newargv[0] = argv[0];
newargv[1] = "-cpu";
newargv[2] = "g4";
memcpy(&newargv[3], &argv[1], sizeof(*argv) * (argc -1));
newargv[argc + 2] = NULL;
return execve("/usr/bin/qemu-ppc", newargv, envp);
}
と書き、gcc -static qemu-ppc-g4-wrapper_chroot.c -O3 -s -o qemu-ppc-g4-wrapper
でバイナリを生成します。これをmv qemu-ppc-g4-wrapper /usr/powerpc-unknown-linux-gnu/usr/local/bin/qemu-ppc-g4-wrapper
に配置します。続いてvim qemu-ppc-g4-wrapper.c
に
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv, char **envp) {
char *newargv[argc + 5];
newargv[0] = argv[0];
newargv[1] = "-cpu";
newargv[2] = "g4";
newargv[3] = "-L";
newargv[4] = "/usr/powerpc-unknown-linux-gnu/";
memcpy(&newargv[5], &argv[1], sizeof(*argv) * (argc -1));
newargv[argc + 4] = NULL;
return execve("/usr/bin/qemu-ppc", newargv, envp);
}
と書き、gcc -static qemu-ppc-g4-wrapper.c -O3 -s -o qemu-ppc-g4-wrapper
でバイナリを生成します。これをmv qemu-ppc-g4-wrapper /usr/local/bin/qemu-ppc-g4-wrapper
でそれぞれに配置します。続いてはbinfmt_miscの設定です。vim /etc/binfmt.d/qemu-ppc-g4.conf
に
:qemu-ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc-g4-wrapper:OC
を記述し、systemctl restart systemd-binfmt.service
で適用します。有効になっているqemuの設定の一覧はls /proc/sys/fs/binfmt_misc/
で確認でき、catで中身を確認できます。
8. Rustのクロスコンパイル設定vim /etc/portage/package.use/cross-rust
に
dev-lang/rust rust-src
を記述mkdir /etc/portage/env/dev-lang
vim /etc/portage/env/dev-lang/rust
にRUST_CROSS_TARGETS=<LLVM target>:<rust-target>:<CTARGET>を記述します。<LLVM target>の確認は、emerge –ask –oneshot llvm-core/llvmした時に確認できるUSEフラグから抽出し、<rust-target>の確認は、rustcのドキュメントから、<CTARGET>はcrossdevのtoolchainインストール時の物を使用します。今回の場合は以下の様です。
RUST_CROSS_TARGETS=PowerPC:powerpc-unknown-linux-gnu:powerpc-unknown-linux-gnu
一度worldemerge -avuDN @world
cd /var/db/repos/crossdev/cross-powerpc-unknown-linux-gnu
ln -s /var/db/repos/gentoo/sys-devel/rust-std
vim /etc/portage/package.accept_keywords/cross-rust
にcross-powerpc-unknown-linux-gnu/rust-std **
を記述、そしてrustのインストールemerge -av cmake
emerge -av cross-powerpc-unknown-linux-gnu/rust-std
9. chroot
まず必要のディレクトリの作成cd /usr/powerpc-unknown-linux-gnu
mkdir var/db/repos/gentoo
mkdir var/db/repos/localrepo-crossdev
mkdir lib/modules
mkdir dev
下のコマンドは毎回打つのが面倒なのでシェルスクリプトにするか、arch-chrootを使うのが良いと思います。
cd /usr/powerpc-unknown-linux-gnu
mount -t proc none proc
mount –rbind /dev dev
mount –make-rslave dev
mount -o bind /var/db/repos/gentoo var/db/repos/gentoo
mount -o bind /var/db/repos/localrepo-crossdev var/db/repos/localrepo-crossdev
mount -o bind /lib/modules lib/modules
mount –rbind /sys sys
mount –make-rslave sys
cp /etc/resolv.conf etc/resolv.conf
chroot . /bin/bash –login
11. なんかシェルスクリプトを実行するとエラーが出る場合
# locale-gen
bash: /usr/bin/locale-gen: cannot execute: required file not found
とか言われます。/bin/bashが存在せず、/usr/bin/bashにしか無いため発生します。ln -s /usr/bin/bash /bin/bash
12. とりあえず、world
chroot外でemerge-powerpc-unknown-linux-gnu -avuDN @world
を行います。
12. なんかemergeするとqemuのエラーが出る
emergeすると
qemu: qemu_thread_create: Invalid argument
とか言われて何もできません。chrootのネットワーク周りの不完全さによるものらしいです。
chroot内でvim /etc/portage/make.conf
のFEATURESに-pid-sandbox -network-sandboxを追加します。
13. なんかfunction.shが無いと言われる
母機の方からコピーしました。chrootから抜けた状態でcp -R /lib/gentoo /usr/powerpc-unknown-linux-gnu/lib/
14. 初期設定ln -s /tmp /usr/powerpc-unknown-linux-gnu/tmp
nano /etc/locale.gen
以下の2つを有効にしました。
en_US.UTF-8 UTF-8
ja_JP.UTF-8 UTF-8
そして適用locale-gen
gccの設定の確認と適用gcc-config -l;ldconfig -v;ROOT=/ env-update; source /etc/profile
emerge用の環境変数の設定echo 'alias emerge-chroot="ROOT=/ emerge"' > ~/.bash_profile && source ~/.bash_profile
15. クロスビルドしたいものをビルド
chroot内ではemerge-chroot、chroot外ならemerge-powerpc-unknown-linux-gnuを使用します。
chroot内はQEMU上で動いているので遅いです。基本的にはemerge-powerpc-unknown-linux-gnuを使用して、エラーが出たらemerge-chrootを使う感じが良いと思います。
クロスビルド中に発生した様々なエラーと対処
1. なんかUSEフラグが自動では設定されない問題への対処法
dispach-confをしても何も出てこないし、–autounmask=y –autounmask-writeオプションを付けても変わりません。dispach-confのあとにパスを指定すればいけました。
chroot外なら、dispach-conf /usr/powerpc-unknown-linux-gnu/etc/portage/package.use
とかで行けると思います。
2. なんかglibがインストールできない
ERROR: An exe_wrapper is needed for /tmp/portage/dev-libs/glib-2.84.3/work/gobject-introspection-1.82.0-build/tools/g-ir-compiler but was not found. Please define one in cross file and check the command and/or add it to PATH.
とかいうエラーが出てしまい進みませんでした。
Bug 850895 – dev-libs/gobject-introspection: cannot cross-compile An exe_wrapper is needed but was not found
Bug 751325 – meson.eclass: Support for setting exe wrapper for crosscompilation
とかを参考にして、直接mesonのファイルを編集して解決させました。
chroot内で、cp /var/db/repos/gentoo/eclass/meson.eclass /var/db/repos/gentoo/eclass/meson.eclass.bak
でバックアップをとって、vim /var/db/repos/gentoo/eclass/meson.eclass
で開いて_meson_create_cross_file()の[binaries]にexe_wrapper = ‘/usr/local/bin/qemu-ppc-g4-wrapper’を追加したところ、chroot内でemerge-chrootでインストールできました。
3. なんかlddがおかしくてnot a dynamic executableしか返さず、パッケージがインストールできない
/usr/powerpc-unknown-linux-gnu/lib/ld.so.1が含まれていないせいで、powerpc用のバイナリを解析できないのが原因でした。vim /usr/bin/ldd
で開いて、RTLDLISTの最後に、/usr/powerpc-unknown-linux-gnu/lib/ld.so.1を追加しました。無事にインストールできるようになりました。
バイナリパッケージの配布とインストール
参考にしたサイト
gentoo linux Wiki「バイナリーパッケージガイド」
ntoofu「Gentoo Linuxで(Portageで)パッケージビルドサーバーを使う」
生成されたバイナリパッケージは
/usr/powerpc-unknown-linux-gnu/var/cache/binpkgs/
に存在します。これのディレクトリをSSHやhttpで公開し、インストールしたいデバイスの/etc/portage/make.confにPORTAGE_BINHOSTを設定することで使用できます。
1. apacheのインストールと実行emerge -av apache
systemctl start apache2
2. シンボリックリンクの作成
なんかデフォルトだと、apache2のルートディレクトリが/var/www/localhost/htdocsなので、横着して、そのままシンボリックリンクを貼り付けました。ln -s /usr/powerpc-unknown-linux-gnu/var/cache/binpkgs/ /var/www/localhost/htdocs/binpkgs
http://IPアドレス/binpk
gs/にアクセスするとパッケージの一覧が見えるはずです。
3. クライアント(バイナリパッケージをインストールする)側の設定vim /etc/portage/make.conf
に、
PORTAGE_BINHOST=http://IPアドレス/binpkgs/
を書きます。
4. バイナリパッケージのインストール
-Gオプションか、–getbinpkgonlyをつけることで、強制的にバイナリパッケージを使用することができます。

おわりに
かなり大変でしたがPowerBook G4にepiphany(GNOME Web)をインストールをすることができました。3回くらいWSLのインストールし直した気がします。
