MBPのApple EFIが自動的に認識するブートEFIファイルについて
この記事はUEFI Advent Calendar 2014 - Qiitaの第9日目として書かれました。
以下の内容はMacBook Pro Retina 13inch (late 2013)を使って検証しました。おそらく、最近のMacBook Pro/Airであれば同様の結果になると思われます。
私はMBP買ったらすぐにGentoo Linuxでシングルブートするマンであり、OS Xに関する部分は以前のメモに頼っている部分もあるため、検証が甘いと思われます(いちおう、SDカード上にOS X Yosemiteを入れて確かめています)。
MacBook Pro(以下MBP)の起動時にジャーンと鳴っている間に[Option]キーを押しておくと、グラフィカルなメニューが表示され、起動させるOSを選択することができます。この起動メニューはApple的にはStartup Managerと言うらしいですね。このStartup Managerに表示される項目について調べました。
Startup Managerに表示される条件
Startup Managerにエントリが表示される条件は、内蔵SSD・USBメモリ・SDカードを問わず、以下の条件を満たすファイルが存在することです。
パーティションテーブルはGPT、MBRパーティションテーブルのいずれでも可です。
上記のEFI起動ファイルが存在していればStartup Managerの起動エントリとして表示されます。複数のファイルが存在していれば優先順位は上記の順番通りです。
更に、ディスクがMBRパーティションテーブルである場合、ブートセクタが起動可能か否かにかかわらず、Windowsというラベルでエントリが表示されます。
このチェックは全てのディスク上のHFS+またはvfatパーティションに対して行われます。GPTのパーティション数は一般に最大128ですので、とてもたくさんのエントリを表示させることができますね(実際に幾つまで表示されるかは確認していません)。
外付け光学ディスクドライブの手持ちが無かったのでそれに関しては検証していません。ごめんなさい。
また、BootCampも使ったことが無いので全くわかりません。ごめんなさい。
Startup Managerの表示について
エントリのアイコンは対象パーティションのルートに/.VolumeIcon.icnsというMacアイコンファイルが存在すれば、それが使われます。GNU/Linuxではpng2icnsというコマンドでMacアイコンファイルを作成できます(Gentooではmedia-libs/libicnsに含まれます)。無ければデバイスに応じたデフォルトアイコンになります。
アイコンの下に表示されるテキストラベルは、HFS+上のブートファイルに対してOSXのbless(8)コマンドのFolder Modeで--labelオプションを指定した場合、その文字列が使われます。ラベルの本体は"blessed"ディレクトリ下にある._disk_label, .disk_label_2xという謎フォーマットのファイルで、--labelで指定したテキストをフォントでレンダリングした謎フォーマットの画像ファイルと思われます。
blessしていない場合またはvfatファイルシステムの場合(当然vfat上のファイルはblessできません)は、"EFI Boot"というラベルになります。
まとめ
ここまででわかる通り、Startup ManagerはEFI変数のBoot Entryとは無関係です。また、当然ながらOSXのエントリはStartup Managerに表示されることが保証されています。OSX 10.9(Marverics)のブートファイルはOSXインストールHFS+上の/System/Library/CoreServices/boot.efiであり、OSX 10.10(Yosemite)のブートファイルはOSX復元パーティションのHFS+上の同じパスにあり、StartupManagerに表示されます。
EFI Stub KernelまたはGNU grubやrEFIndなどの汎用ブートローダ、はたまたEFI Shellなどをインストールする場合、上記のデフォルトエントリに置くか、HFS+上に置いてblessするだけで、Startup Managerから起動できます。EFI変数(NVRAM)を変更する必要すらありません(blessコマンドは--setBootオプションを指定しない限りNVRAMを変更しません)。これはEFI非対応の環境からLinux等をインストールする場合にも便利です。
私がどう利用しているかというと、EFI Stub KernelのBoot Entryを作り、BootOrderの先頭に設定して(vfat上に置いていますがデフォルトパスではないのでStartup Managerからは選択できない)普段はこれを起動しつつ、更に小さなvfatパーティションを2つ用意してそれぞれのEFIデフォルトブートパスにGNU grubとEFI Shellを置いてStartup Managerから選択できるようにしてあります。
EFI Shellに(rEFIndパッケージから持ってきた)ファイルシステムドライバを読み込ませることで、EFI ShellからExt4やbtrfsにアクセスできるのは大変便利です。
おまけ
BootOrderの設定されていない状態では何が起動するか。
efibootmanager --delete-bootorderしてBootOrderを空にしてからMBPを起動させると、単純にSSD上の先頭パーティションから順に検索して起動可能なEFIファイルを起動します。この際、自動的に、発見されたEFI起動ファイルをEFI変数のBoot EntryとしてBoot0080とBootFFFFに保存し、更にBootOrderにBoot0080を設定します。
この挙動の通り、購入直後のMBPにはOSXのboot.efiを指すBoot0080とBootFFFFが登録されていて、BootOrderも0080が設定されていました。
systemdのこと
systemd使ってますか
Gentoo Linuxでもsystemdを使う人が増えてきた今日このごろ、皆さんもsystemdしているでしょうか。私はしていません。でもVirtualBox上のGentoo Linuxではしばらく前からsystemdを使っています。私は根っからのデスクトップユーザにしてアプリケーションユーザなので、技術的な考察などは守備範囲外なのですが、取り敢えずOpenRCとsysytemdとの違いとしてわかりやすい、起動時間の差を動画にしてみました。
ちょっと動画について補足説明します。
OpenRCはRC_PARALLEL="yes"を設定しています。
OpenRCで/etc/init.d/net.*ではなく/etc/init.d/dhcpcdを実行させています。こうすればdhcpcdがアドレス割り当てをバックグラウンドで待ちますので、若干他のサービス起動が速くなる、かもしれない。ricer的ですね……。
OpenRCと条件を揃えるために、systemdでもsyslog-ng, vixie-cron, ConsoleKitのサービスを起動しています。ですが、systemdではこれらのサービスが提供する機能をsystemdビルトイン機能で概ね置き換えることができます。
- syslog -> systemd-journald
- cron -> Timer unit
- ConsoleKit -> systemd-logind
ということでsystemdではこれらのServiceを起動しなくても良いのですが、実は起動してもしなくても起動所要時間がほとんど変わらない(!!)ということがわかりました。systemd-analyzeによると、これら3つのサービスを起動した場合のuserspace起動時間は3309ms、起動しない場合は3005msとなって、0.3秒しか変化はありませんでした。
syslog-ngはin tree ebuildでインストールされるunitファイルが使えないので、野良リポジトリから新しいバージョンを入れています。
vixie-cronはunitファイルをインストールしないので、unitは自分で用意します。書くのは簡単ですが、このへんにも色々あります。
これからどうするの
日常的に使ってるGentoo Linux環境のsystemdへの本格的な移行は、今の所考えていませんが、いずれは移行しなきゃならないのかなあ。udevがsystemdが無いと動かなくなったら仕方ないですね。当面、それよりも先に問題になりそうなのはsystemd-logind関係で、現状既にConsoleKitはUpstream Dead、upowerもpm-utilsサポートをドロップしてsystemdの機能を使うことになりそうです。でもUbuntuがsystemd-logindを移植するような話が出ているので、どうなることやら。
HALが終わってデスクトップLinuxがpolkit/ConsoleKit/udisks/upowerに移行したのってたった3年くらい前の話なんですよね。もう3年経ったと言うべきなのか?
KBUILD_OUTPUT環境変数: Linuxカーネルは一般ユーザでビルドしよう
最近になってKBUILD_OUTPUTという環境変数を知ったので、そのことについて書きます*1。
Linux Kernelを一般ユーザでビルドしたい。
パッケージマネージャを利用してLinux Kernelをインストールすると、/usr/src以下に配置されます。パーミッションはroot:rootなので、当然一般ユーザではビルドできません。
$ make menuconfig HOSTCC scripts/basic/fixdep scripts/basic/fixdep.c:433:1: fatal error: opening dependency file scripts/basic/.fixdep.d: 許可がありません コンパイルが中断されました。 make[1]: *** [scripts/basic/fixdep] エラー 1 make: *** [scripts_basic] エラー 2
当然ながら、カーネルビルド時のオブジェクトファイル群を別のディレクトリに生成させるオプションが用意されています。以下はLinux KernelのMakefileから該当部分。
# kbuild supports saving output files in a separate directory.
# To locate output files in a separate directory two syntaxes are supported.
# In both cases the working directory must be the root of the kernel src.
# 1) O=
# Use "make O=dir/to/store/output/files/"
#
# 2) Set KBUILD_OUTPUT
# Set the environment variable KBUILD_OUTPUT to point to the directory
# where the output files shall be placed.
# export KBUILD_OUTPUT=dir/to/store/output/files/
# make
#
# The O= assignment takes precedence over the KBUILD_OUTPUT environment
# variable.
Makefileを読んでしまえば今日の記事の内容はだいたいおしまいなのですが、一応説明を続けます。
make O=
まずはmake O=。カーネルビルドに必要なオブジェクトファイル群が、O=で指定したディレクトリに生成されるようになります。
$ make O=~/work/kernel-build/3.6.6-gentoo menuconfig $ make -j5 O=~/work/kernel-build/3.6.6-gentoo # make O=/home/tomo/work/kernel-build/3.6.6 modules_install install
ところで、Gentooでは各ユーザがそれぞれ自前でビルドしたKernelを利用するのが基本です。なので、
・パッケージマネージャは、必要に応じてユーザのカーネルが適切に設定されているかチェックできなければならない。
・ビルドにカーネルソースが必要なパッケージ(例えば外部カーネルモジュール)をインストールする場合、カーネルソース及びビルドオブジェクトがどこに存在するかパッケージマネージャは知っていなければならない。
ということで、上記make O= を利用してカーネルビルドすると、例えばこんなことになります。
# emerge --ask --verbose @module-rebuild (snip) * NVIDIA-Linux-x86_64-304.64.run SHA256 SHA512 WHIRLPOOL size ;-) ... [ ok ] * Determining the location of the kernel source code * Found kernel source directory: * /usr/src/linux * Found sources for kernel version: * 3.6.6-gentoo * Could not find a usable .config in the kernel source directory. * Please ensure that /usr/src/linux points to a configured set of Linux sources. * If you are using KBUILD_OUTPUT, please set the environment var so that * it points to the necessary object directory so that it might find .config. * ERROR: x11-drivers/nvidia-drivers-304.64 failed (setup phase): * Kernel not configured; no .config found in /usr/src/linux (snip)
カーネル設定をチェックするためにビルドシステムは.configファイルを探していますが、.configはO=で指定したディレクトリに作成されているので/usr/src/linux以下には見つからず、エラーになりました。
KBUILD_OUTPUT
ということで、今日の本題であるKBUILD_OUTPUT。この変数は環境変数として利用するのが普通です。Gentooでシステム環境変数を設定する場合は/etc/env.dを使います。
# echo 'KBUILD_OUTPUT="/home/tomo/work/kernel-build/current"' > /etc/env.d/90kbuild_output # env-update && source /etc/profile $ cd ~/work/kernel-build $ mkdir 3.6.6-gentoo && ln -sfn 3.6.6-gentoo current (Kernelアップグレードの度にいちいち環境変数を切り替えるのは面倒なので、 私はKernelバージョンごとのディレクトリ -> currentというシンボリックリンクにしています)
環境変数に設定したので、あとは普通にビルドするだけです。
$ cd /usr/src/linux $ make menuconfig $ make -j5 # make modules_install install (sudoを利用する場合は、 sudo実行環境に環境変数を渡すために/etc/sudoersにenv_keepを設定するか、 sudo -lとして実行する必要があります)
ebuildビルドシステムは、KBUILD_OUTPUTを参照してカーネルビルドオブジェクトを探してくれます。
* Determining the location of the kernel source code * Found kernel source directory: * /usr/src/linux * Found kernel object directory: * /home/tomo/work/kernel-build/current * Found sources for kernel version: * 3.6.6-gentoo >>> Unpacking source... ...
ということで、GentooではKBUILD_OUTPUTを設定しておくと便利という話でした*2。一般ユーザでビルドする=rootでの作業を減らすという点よりも、ソースディレクトリとビルドディレクトリを分けておけば、パッケージマネージャでカーネルソースをアンインストールした時にきれいに消えてくれるし、git sourceを利用している場合もツリーを汚さずに済むのでよりエレガントではないでしょうか。
ちなみに、Linux Kernelのソースディレクトリ自体を別の場所に置きたい場合は、シンボリックリンク/usr/src/linuxをソースディレクトリにポイントする方法の他に、KERNEL_DIR変数を設定する方法もあります。これは基本的にパッケージマネージャだけが利用する変数なので、make.confにでも書いておけばいいでしょう。
# echo 'KERNEL_DIR=/home/tomo/work/src/linux/git-torvalds' >> /etc/portage/make.conf
Gentooのパッケージマネージャ = ebuildビルドシステムがどのようにカーネルオブジェクトディレクトリやカーネルソースディレクトリを検索するのかは、linux-info.eclassを見てください。例えば、ソースディレクトリにビルドオブジェクトが存在せず、KBUILD_OUTPUTも設定されていない場合には、/lib/modules/$(uname -r)/build symlinkがオブジェクトディレクトリであるとみなします。こうなってしまうと、「新しいKernelをビルド/インストールし、新しいKernelで起動する前にモジュール類を再ビルドしておく」状況で問題になりますので、注意する必要がありますね。
GentooからPortageを完全に削除してPaludisを使おう
前回はPortageの代替としてPaludisとpkgcoreを紹介しました。では、いっそGentooからPortageを消してしまうとどうなるの、という話です。
Portageを消してしまおう
PaludisのFAQを見ると、こう書いてあります。
Remove Portage from my Gentoo installation
The short answer is that you can't.
Several Gentoo packages wrongly depend on Portage, several depend on Portage because they use it and there really is no reason to try. Just leave Portage installed.
この文書は既に古いという意見もあります。そこにはこう書いてあります。
Are there still lots of packages that use Portage but don't say so? e.g. gcc-config...
とにかく色々と問題はありそうなわけですね。
でも消します。
消してしまってから考える
cave uninstall sys-apps/portage --uninstalls-may-break virtual/package-manager --uninstalls-may-break app-admin/python-updater -x rm -rf /etc/make.conf /etc/make.profile /etc/make.globals /etc/portage /usr/portage /var/lib/portage /var/cache/portage /var/tmp/portage
virtual/package-managerとapp-admin/python-updaterのportageへのDEPENDはいずれもchoice dependencyだったので、無視させました。
Portageの設定ファイルなどが残っていると、それを利用するコマンドもありそうなので、全て消します。また、gentooリポジトリやworldファイルの配置場所なども全てPortageのデフォルトと別の場所になるようにPaludisを設定しています*1。
では問題をひとつひとつ解決していきます。
設定ファイルの更新コマンドがない
パッケージアップグレードでCONFIG_PROTECTされた設定ファイルが置き替えられる場合、それをマージするためのコマンドが必要です。etc-update, dispatch-confはsys-apps/portageに含まれるコマンドなので、Portageを消すと当然使えなくなります。以下の代替コマンドがあります。
このうち、Portage以外のパッケージマネージャ対応という点ではcfg-updateが一番良いようです。オプション--paludisを付けることでPaludisの設定を利用して実行されます。
cfg-update -l --paludis cfg-update -u --paludis
env-updateがない
/etc/profile.envおよび/etc/ld.so.confの生成を行うenv-updateもsys-apps/portageに含まれているので、当然使えなくなります。これはapp-admin/eselectの基本モジュール、eselect.envで代替できます。
eselect env update
eselect env update --noldconfig
gcc-configが動かない
sys-devel/gcc-configはPortageが無いと動かないらしいですね。やってみましょう。
amd64vbox ~ # gcc-config -l * gcc-config: Could not get portage CHOST! * gcc-config: You should verify that CHOST is set in one of these places: * gcc-config: - //etc/portage/make.conf * gcc-config: - active environment
はい動きません。
システムにpythonがある場合にはportageqコマンドでCHOSTを取得してますね。あとで書きますが、Pythonは消せないので他の手段を探します。変数REAL_CHOSTが定義されていればそれを使ってくれるみたいなので、やってみます。
amd64vbox ~ # REAL_CHOST="x86_64-pc-linux-gnu" gcc-config -l [1] x86_64-pc-linux-gnu-4.4.6 * [2] x86_64-pc-linux-gnu-4.5.3 amd64vbox ~ # REAL_CHOST="x86_64-pc-linux-gnu" gcc-config 2 * Switching native-compiler to x86_64-pc-linux-gnu-4.5.3 ... /usr/bin/gcc-config: line 362: env-update: command not found * env-update failed to work properly; making sure ld.so.conf paths * are setup properly. Please rerun gcc-config with the -f option. [ ok ]
今度はエラーにはなりませんでしたが、env-updateが無いと言われています。eselect env updateで代替できるのはわかっているので、ごまかします。
/usr/local/sbin/env-update #!/bin/bash eselect env update
binutils-configも動かない
sys-devel/binutils-configもgcc-configと似たようなことになります。
amd64vbox ~ # binutils-config -c /usr/bin/binutils-config: line 314: portageq: command not found * binutils-config: No binutils profile is active!
変数CHOSTが正しく定義されていれば実行できます。
amd64vbox ~ # CHOST="x86_64-pc-linux-gnu" binutils-config -c
x86_64-pc-linux-gnu-2.21.1
実際に設定を変更する場合には、gcc-configと同様にenv-updateが呼ばれます。これまたgcc-config同様、env-update実行が失敗しても警告を出すだけで正常終了します。
ちなみに、gcc-config, binutils-configはgccやbinutilsのインストール時にtoolchain{-binutils}.eclassから呼ばれます。Paludisのebuild処理においてはCHOST及びREAL_CHOSTが定義済みなので、エラーにはなりません*2。
どこかで問題が出るかもしれませんが、REAL_CHOSTとCHOSTを環境変数にしてしまえば毎回指定しなくても済みますね。
/etc/env.d/00real-chost REAL_CHOST="x86_64-pc-linux-gnu" CHOST="${REAL_CHOST}"
Gentoo黒魔術の大物、Java
Java周りはかなりやっかいです。
dev-java/java-config-wrapperに含まれるjava-1.5-fixerはemergeを使用します。java-check-environmentはportageqを使用します。なので、Portageを削除すると色々と動かなくなります。
dev-java/java-configに含まれるdepend-java-queryはPortageのPython Moduleを利用するので、正常に動かなくなります。
それだけなら別にいいんですが(よくない)、この辺りのコマンド類はjava-*.eclassで利用されるため、Java関係のパッケージのインストールが軒並み失敗するようになります。
例えばこんな感じ。
>>> Starting pkg_setup !!! ERROR: No module named portage_dep * Unable to determine VM for building from dependencies: Error: * In program cave perform install --hooks --managed-output --output-exclusivity with-others =media-libs/libjpeg-turbo-1.2.0-r1:0::gentoo --destination installed --replacing =media-libs/libjpeg-turbo-1.2.0-r1:0::installed --x-of-y 15 of 15: * When installing 'media-libs/libjpeg-turbo-1.2.0-r1:0::gentoo' replacing { 'media-libs/libjpeg-turbo-1.2.0-r1:0::installed' }: * When running an ebuild command on 'media-libs/libjpeg-turbo-1.2.0-r1:0::gentoo': * Install failed for 'media-libs/libjpeg-turbo-1.2.0-r1:0::gentoo' (paludis::ActionFailedError) NV_DEPEND: !media-libs/jpeg:0 amd64? ( || ( dev-lang/nasm dev-lang/yasm ) ) x86? ( || ( dev-lang/nasm dev-lang/yasm ) ) amd64-linux? ( || ( dev-lang/nasm dev-lang/yasm ) ) x86-linux? ( || ( dev-lang/nasm dev-lang/yasm ) ) java? ( >=virtual/jdk-1.5 ) java? ( >=dev-java/java-config-2.1.9-r1 ) !!! ERROR in media-libs/libjpeg-turbo-1.2.0-r1::gentoo: !!! In java-pkg_switch-vm at line 4473 !!! Failed to determine VM for building. !!! Call stack: !!! * java-pkg_switch-vm (/var/tmp/paludis/media-libs-libjpeg-turbo-1.2.0-r1/temp/loadsaveenv:4473) !!! * java-pkg_init (/var/tmp/paludis/media-libs-libjpeg-turbo-1.2.0-r1/temp/loadsaveenv:3950) !!! * java-pkg-opt-2_pkg_setup (/var/tmp/paludis/media-libs-libjpeg-turbo-1.2.0-r1/temp/loadsaveenv:3211) !!! * pkg_setup (/var/tmp/paludis/media-libs-libjpeg-turbo-1.2.0-r1/temp/loadsaveenv:5188) !!! * ebuild_f_setup (/usr/libexec/paludis/0/pkg_setup.bash:43) !!! * ebuild_main (/usr/libexec/paludis/ebuild.bash:646) !!! * main (/usr/libexec/paludis/ebuild.bash:672) diefunc: making ebuild PID 11027 exit with error die trap: exiting with error. Failed install to / for media-libs/libjpeg-turbo-1.2.0-r1:0::gentoo replacing 1.2.0-r1:0::installed
このエラーに関しては、depend-java-queryはPortageのモジュールを利用しなくても実はちゃんと動いている(ように見える)ので、豪快にごまかしてみました。
--- src/java_config_2/VersionManager.py.orig +++ src/java_config_2/VersionManager.py @@ -132,7 +132,7 @@ # Remove conditional depends that are not turned on atoms = " ".join(flatten(use_reduce(paren_reduce(atoms),uselist=use))) - except KeyError: + except (ImportError, KeyError): pass return atoms
上記のエラーはmedia-libs/libjpeg-turbo[java]で発生したものですが、取り敢えずこれでインストールはできるようになりました。
取り敢えず他にも試そうということで、dev-java/icedtea6-binとdev-java/sun-jdkの両方を入れて切り替えつつapp-editors/jeditをインストールしてみたりしましたが、今のところ問題は出ていません。
私が普段使っている環境ではJavaを利用するパッケージが少ないので、問題に遭遇することも少なかったのですが、ガシガシJava関連パッケージを利用する場合にはどこかでドツボに嵌りそうな予感がひしひしとします。
その他、特に問題のないところ
- app-admin/perl-updater, app-admin/*-updater
perl-cleaner, *-updaterなどのコマンドは、対象のアップグレードが行われたあとに実行すると、更新が必要なパッケージを自動的に再インストールしてくれます。perl-cleanerは>=2.8からPaludis(caveコマンド)に対応しています。haskell-updater, python-updaterは現在gentooリポジトリにあるものは全てPaludisに対応しているようです。
- sys-auth/pambase
pambaseのebuild内でqatomコマンドを使っているのでapp-portage/portage-utilsにDEPENDしています。幸い、qatomの動作はパッケージマネージャに依存しないので、Portaeを削除していてもちゃんと動作します。pambaseのインストールも問題ありません。
- revdep-rebuild
前回の記事にも書きましたが、Paludisにはrevdep-rebuildに対応する機能が最初からあります。
cave fix-linkage
感想と結論
Portageを消すことで、「Gentooとは選択です」を実現するための黒魔術の一端に触れることができました。えっそんな結論。
Portageを消すことで色々と問題には遭遇しますが、なんとかごまかしつつ、使えています。私が普段使っている程度の環境を運用するのなら特に問題ない、と言えなくもないというところです。しかしこれまでは何とかなっていますが、次に遭遇するトラブルは解決できるとは限らないし……。
そして、実はPortageを消しても特にメリットはないので、まあやらなくても良いですかね。現状では基本的に自己満足の世界です。そして私的には結構満足なのです*3。
そうだ、Portage消せるのならPythonも要らないんじゃね!?
と思ったのですが、sys-apps/paludisはdev-cpp/gtestにDEPENDしており、dev-cpp/gtestはdev-lang/pythonにDEPENDしていました……。つまりPortageを消してもPythonは必要でした。うーん残念。
cave importのご紹介
gcc-configが警告を出さなくなるように、/usr/local/sbin/env-updateというスクリプトを手動で用意しましたが、/以下のファイルは須らくパッケージマネージャの管理下にあるべし、という方にはcave importがオススメです。
まずinstalled_unpackagedリポジトリを用意しておきます。
amd64vbox ~ # cat /etc/paludis/repositories/installed_unpackaged.conf format = installed_unpackaged location = /var/db/paludis/repositories/installed_unpackaged amd64vbox ~ # mkdir -p /var/db/paludis/repositories/installed_unpackaged amd64vbox ~ # chown paludisbuild:paludisbuild /var/db/paludis/repositories/installed_unpackaged
適当にディレクトリを掘って、インストールしたいファイルを配置します。
amd64vbox ~ # mkdir -p DESTDIR/usr/sbin amd64vbox ~ # cp env-update DESTDIR/usr/sbin amd64vbox ~ # mkdir -p DESTDIR/etc/env.d amd64vbox ~ # cp 00real_chost DESTDIR/etc/env.d
適当なカテゴリ/パッケージ名を指定してcave importします*4。
amd64vbox ~ # cave import --location ./DESTDIR sys-apps/portage-compat -x
すると、こんな具合にPaludisで管理できます。
amd64vbox ~ # cave show sys-apps/portage-compat * sys-apps/portage-compat ::installed-unpackaged 0 {:0} sys-apps/portage-compat-0:0::installed-unpackaged (world) Description Installed time Mon Mar 19 19:15:31 JST 2012 Source repository unpackaged amd64vbox ~ # cave contents sys-apps/portage-compat /usr /usr/sbin /usr/sbin/env-update /etc /etc/env.d /etc/env.d/00real_chost
消したくなったらcave uninstallで消せます。cave importは依存関係も記述できるのですが、blockerには対応していない*5のがちょっぴり残念です。
Portageの代わりにPaludisを使ってみよう。
PortageはGentooシステムの中核をなすパッケージマネージャであり、Gentooの最大の魅力とも言われています。
つまりGentoo = Portage? いいえ!!
❝Gentooとは選択です❞
Gentooは選択なので、パッケージマネージャもまた選択の対象です。sys-apps/portageはGentooの中核パッケージセット = system setには含まれていません。ではsystem setで要求されているのは何かと言うと、virtual/package-managerです。virtual/package-managerでは以下の3パッケージが列挙されており、いずれかがインストールされます。
- sys-apps/portage
- sys-apps/paludis
- sys-apps/pkgcore
残念ながら、portage以外は全てunstable扱いです。更に残念なことに、Portageに暗黙に依存しているパッケージ*1も存在するために、PortageをGentooからはぎ取るのは結構困難ですね*2……。
でも普段はパッケージマネージャとしてPortage以外を使ったって全然問題ないのです。
Paludisを使おう。
そんなわけでPaludisを使いましょう。Paludisには以下のような特徴があります。
インストールするには。
emergeしましょう。それだけだ。eselect package-manager set paludisもしておくと良いかも。
Paludisの設定。
Paludis公式サイトのGetting Startedを読みましょう。
portage USEフラグを有効にすると一応Portage用の設定ファイルを読み込んで動作しますが、あまり当てにならないので自分でPaludis専用の設定ファイルを書くのが確実です。portage2paludisスクリプトを利用して自動作成し、説明を読みながら書き直すのが一番簡単かなと思います。
Paludisの利用。
Portageにおけるemergeに対応するのはcaveコマンドです。
(ついでに言えばpkgcoreではpmerge, pmaintです)
以下の例ではportage-2.2_alpha86、paludis-0.72.0、(ついでにpkgcore-0.7.7.8)を使用しています。
- リポジトリのリモートとの同期
emerge --sync
cave sync
pmaint sync
caveのsyntaxルールはcave アクション 引数 (-オプション)という具合で、gitっぽい感じですね。
Paludisとpkgcoreはマルチリポジトリ対応なので、syncすると登録された全てのリポジトリが同期されます。
- パッケージのインストール
emerge パッケージ名 cave resolve パッケージ名 pmerge パッケージ名
caveは対話的に動作しませんので、emergeの-a, --askや-p, --pretendに対応するオプションはありません。
オプション無しでcave resolveを実行するとemerge --pretend同様に実際には何もしません。
本当にアクションを実行する場合にはオプション-x, --executeを付けます(幾つかのアクションは-xオプションがなく、即時実行されます)
caveには -v, --verboseに対応するオプションは無く、常に饒舌です。
インストールにあたってUSE flagsやACCEPT_KEYWORDに修正が必要な場合にサジェストしてくれるのはいずれのパッケージマネージャも同じですが、総じてPortageのメッセージの方が親切でわかりやすいように思います。
Blockerがあった場合も解決方法をサジェストしてくれますが、Paludisでは-U, --permit-uninstallや-d, --permit-downgradeなどのオプションを使うとUpgrade時のBlockerを自動的に処理できたりします。Blocksパッケージを手動でアンインストールしなくて良いということですね。
- パッケージのアンインストール
emerge -c パッケージ名 (emerge --depclean パッケージ名) cave uninstall パッケージ名 cave resolve \!パッケージ名 pmerge --unmerge パッケージ名
resolveの引数に!パッケージ名とすると、インストールの逆の動作、つまりアンインストールします(シェルが"!"を解釈しないようにエスケープする必要があります)。
pmergeには依存関係を考慮して削除するオプションはありません。
- インストール済みのシステムを最新に更新する。
emerge -uDN --with-bdeps=y world (emerge --update --deep --newuse --with-bdeps=y world) cave resolve world -B -ks -Sx -sx pmerge --upgrade --deep --newuse --with-built-depends @system @world
emergeでの例は--with-bdeps=yなので、これはややパラノイア的ですね。またemergeの-N, --newuseオプションはebuild内部でのUSE Flag変更も検知します。Paludisとpkgcoreはそこまでしません。
caveの面白いオプションとしては、-R, --reinstall-scmというのがあります。SCMパッケージ(いわゆるlive ebuild)が最後にインストールされたのが一日以上前(-Rd)あるいは一週間以上前(-Rw)であれば、再インストールします。
caveにオプション-c, --completeを付けると-ks -Rw -Sa -sa -Bを付けたのと同じ意味になります。
PortageやPaludisと違い、pkgcoreでのworld setはsystem setを暗黙に含まないので、ターゲットに両方を列挙しています。
- システムから不要なパッケージを削除する。
emerge -c (emerge --depclean) cave purge pmerge --clean --with-built-depends
後で詳しく書きますが、PaludisではSLOT及びchoice dependencyの扱いがPortageやpkgcoreと違っています。なのでemerge --depcleanで消えるパッケージがcave purgeでは消えないことがしばしばあります。
- モー!!
emerge --moo
cave moo
pkgcoreではLarry君に逢えませんね……。バグでしょうか。
マルチリポジトリ、さらに色々なリポジトリ。
Paludisは複数リポジトリに対応しています。
Gentooユーザにとっては基本となるのはgentooリポジトリですね。おっと、Paludisの文書でも釘を刺されていますが*3、gentooリポジトリをPortageツリーなんて言ってはいけません。Portage以外でも使えるわけですから。gentooリポジトリ、gentoo-x86などと呼びましょう;-)
gentooリポジトリの設定例。
/etc/paludis/repositories/gentoo.conf
location = /usr/portage sync = rsync://rsync.jp.gentoo.org/gentoo-portage profiles = /usr/portage/profiles/default/linux/x86/10.0 distdir = /usr/portage/distfiles format = e names_cache = /var/cache/paludis/names
Gentooで利用できるebuildリポジトリはたくさんあります。それらもgentooリポジトリと同様に書くことができます。自分で書くのが面倒くさい場合には、app-portage/laymanから利用できるリポジトリに関しては、playmanコマンド(Paludisのruby-bindings USEフラグを有効にするとインストールされます)をlaymanの代わりに使えます。ただし、(p)laymanで提供されるリポジトリに関しては次に書くunavailable/repositoryリポジトリを使って利用する方法が推奨されています。
repositoryリポジトリとunavailableリポジトリ。
unavailableリポジトリは「まだ設定されていないリポジトリ」の情報を保持するリポジトリです。
repositoryリポジトリはunavailableリポジトリの情報を元に「リポジトリ設定を自動構成するためのリポジトリ」です。
「リポジトリ」がゲシュタルト崩壊しつつあります。
unavailableリポジトリの設定。
/etc/paludis/repositories/layman.conf
format = unavailable name = layman location = /var/db/paludis/repositories/layman sync = tar+http://git.exherbo.org/layman_repositories.tar.bz2 importance = -100
Overlayの情報をダウンロードして利用するlaymanという名のunavailableリポジトリを作りました。
repositoryリポジトリの設定。
/etc/paludis/repositories/unavailable.conf
format = repository config_filename = /etc/paludis/repositories/%{repository_template_name}.conf config_template = /etc/paludis/repository.template
リポジトリ設定ファイルのテンプレートとして/etc/paludis/repository.templateも作ります。
format = %{repository_template_format} location = /var/db/paludis/repositories/%{repository_template_name} sync = %{repository_template_sync} master_repository = gentoo
すると、普通のパッケージのようにインストールすることでリポジトリを追加できます。
cave resolve repository/betagarden -x -1
便利な副作用として、unavailableリポジトリは各リポジトリに含まれるパッケージ情報を含むので、まだインストールされていないリポジトリに含まれるパッケージもcaveコマンドで参照できるようになります。eix-remoteみたいな感じですね。
installed-unpackagedリポジトリ
cave importコマンドで、パッケージングがされていないディレクトリツリーをあたかもパッケージであるかのようにインストールできます。installed-unpackagedリポジトリはそのためのリポジトリです。
例えば、ごく一般的にソフトウェアをビルドして、
$ configure --prefix=/usr && make DESTDIR=/home/user/path install
出来上がったソフトウェアのディレクトリツリーをcave importします。
# cave import --location /home/user/path hoge/fuga
すると、/home/user/path以下のディレクトリ構成がhoge/fugaというパッケージとして/にインストールされ、Paludisで管理できるようになります。必要であればオプションで依存関係も定義できます。
空のディレクトリをcave importすれば、Portageのpackage.providedの代わりになりますね。
ebuildは簡単に書けるのが売りですが、ソフトウェアのビルド形態・配布形態によっては面倒なこともあります。そういう時にはかなり便利ではないでしょうか。ちなみに、Paludisはインストール時にファイルの衝突を検知しないので、システムを壊すようなディレクトリツリーをインストールしてしまわないように気を付けましょう……。
Paludisの提供する機能。
Paludisは、Portageでは外部ツールで提供されている機能を内蔵しています。
- パッケージの詳細情報を表示します。
cave show パッケージ名 eix パッケージ名 (app-portage/eix)
showアクションのターゲットはパッケージ名だけでなく、setやrepositoryにもできます。
cave show repository/betagarden (betagardenリポジトリの情報を表示) cave show @system (system set に含まれるパッケージを列挙)
- パッケージに含まれるファイルを列挙します。
cave contents パッケージ名 qlist パッケージ名 (app-portage/portage-utils) equery files パッケージ名 (app-portage/gentoolkit)
- ファイルがどのパッケージに含まれているのか示します。
cave owner ファイル qfile ファイル (app-portage/portage-utils) equery belongs ファイル (app-portage/gentoolkit)
- ライブラリのsoname変更で壊れたパッケージをインストールしなおす。
cave fix-linkage revdep-rebuild (app-portage/gentoolkit)
ちなみに、pkgcoreではpqueryというコマンドでパッケージその他の情報を表示でき、これも非常に強力です。
外部ツールとの連携とか。
VDB*4はPortageと互換性があるので、app-portage/eixやapp-portage/gentoolkit, app-portage/portage-utilsなどに含まれるユーティリティも一部は利用できます。ただし多くのコマンドがPortageの設定ファイルやログファイルを元に情報を表示するので、正しい結果が得られないことがあります。
非互換部分。
Paludisは自身の扱うファイル/ディレクトリのownerがpaludisbuild:paludisbuildであった方が色々と幸せですが、Portageやpkgcoreと混ぜて使うとパーミッションが変わってしまいます。まあ混ぜなきゃ良いんだよ。
- worldファイルの扱い。
Portageでは、ユーザがsetをインストールするとworld_setsファイルに追加されます。特殊なset(@preserved-rebuildなど)はemergeしてもworld_setsには追加されません。
Paludisでは、cave resolve setしてsetをインストールするとworldファイルにsetを追加します。また、unavailableリポジトリを利用してリポジトリをインストールすると、それもworldに追加されます。いずれの場合も、Portageとの互換性は破壊されます。
worldファイルに記述されるパッケージ情報には、SLOTを含めることができます。
emerge --noreplace sys-kernel/gentoo-sources:3.2.1-r1
cave update-worldコマンドの引数となるターゲットはSLOT情報を含んではいけないので、以下はエラーになります。
cave update-world sys-kernel/gentoo-sources:3.2.1-r1
しかしPaludis自体はworldに記述されたSLOT情報を正しく認識します。ですから必要ならば直接worldを編集すれば良いですね。
pkgcoreはworldに書かれたSLOT情報を無視します。
- SLOT、choice dependency。
Paludisでは、複数SLOTが存在するパッケージに対して依存元がSLOTを明示していない場合、全てのSLOTが必要であると解釈されます。例えばバージョン違いの複数のsys-kernel/gentoo-sourcesをインストールしている場合、各バージョンに応じたSLOTで分けられていますが、virtual/linux-sourcesがどのSLOTを必要としているかは不明なので、全てのSLOTが保持されます = cave purgeで削除されません。同様に、worldに記録されているパッケージも、SLOTが明記されていなければ、全てのSLOTが保持されます。
Portageの場合は依存SLOTが明示されていない場合は最新のSLOTのみを残します。
choice dependencyとはebuildで
RDEPEND="|| ( category/pkg1 category/pkg2 ....
のように書かれている依存関係で、列挙されているうちのいずれかがインストールされれば依存関係を満たします。Portageの場合、もっともリストの先頭に近いパッケージのみが保持され、他は(別の依存関係に組み込まれていなければ)--depcleanで消えます。しかしPaludisでは列挙されているいずれのパッケージも削除されません。こちらはちょっと理屈と合わない気もしますけど、よくわかりませんでした。誰か説明してくれるとうれしいです。
- VDBの非互換。
VDBは概ね互換性がありますが、保存されるenvirionment.gzには相違点があります。Paludisとpkgcoreは非互換で、Paludisでインストールしたパッケージをpkgcoreでアンインストールしたりするとエラーになります(その逆は大丈夫です)。また、Portage <-> pkgcore, Portage <-> Paludisの相互運用は問題ないようです。
まとめ。
Paludisを使ってみると、PortageはGentooの特徴/魅力のごく一部分だということがわかります。Gentooの特徴といえば第一にパッケージマネジメントについて挙げる方が多いと思いますが、その魅力のほとんどはPMS*5とebuild*6、そしてgentooリポジトリの特徴であり、Portageに限定されたものではないのです。Portageを使わなくてもGentooはGentooだよ!!
それともうひとつ、今気付いたのですが、Paludisを入れておくと万が一Portageが壊れてしまった時にとても役に立ちますね。これでもうPythonを壊してしまっても大丈夫というわけです。でもVDBが壊れたらダメなものはダメなんだけど*7。
ということでみんなもPaludisを使ってみませんか。
Paludisだけ使っているとGentoo本家へのBug Report時にちょっと困っちゃうんですけどね……。
*2:実際にPortageを削除してしまったらどうなるかもいずれ試します
*3:The main Gentoo repository, sometimes annoyingly called 'the Portage tree'
*4:/var/db/pkg: インストール済みパッケージのデータベース
*5:Package Management Specification app-doc/pms
*7:If you deleted /var/db/pkg by accident, you're pretty much screwed. So don't do that, and be more careful next time. If you deleted /var/db/pkg on purpose, please install OS X and stop pestering us.
Anaconda Gentoo Installerを使ってみたよ。
起動前の注意点。
anacondaは本来、テキストコンソール上でもX上でも動くようにデザインされていますが、Anaconda Gentoo InstallerはX11 GUIしか用意されていませんので、X上の端末エミュレータでliveinstと打って起動しましょう。一般ユーザで起動して大丈夫です。
また、Oxygen-Gtkテーマエンジンのバグ(たぶん)により、当該テーマを使用していると途中でUIが応答しなくなります。Gentoo LiveDVD 11.2ではKDE及びXfce4のデフォルトテーマがOxygen-Gtkなので、Gtkテーマを変更するか、他のデスクトップ環境/ウィンドウマネージャを利用しましょう。
実行中は特に面白いこともないので箇条書きしますよ。
- 言語設定では、選択する言語に対応するlocale dataを先に作っておきましょう。
- この画面でCFLAGSなどが設定できます。ここで-march= を未定義のまま進めると、後でgccが呼ばれたときにerror: bad value (None) for -march= switch という素敵なエラーを食らいます。ちゃんと設定しましょう。
- ミラーサイト設定画面があるのですが、これはモックアップで実際には何も設定されません……。
- System ProfileとUSE Flagsを選択できます。ただし設定できるのはGlobal USE Flagsのみで、各パッケージ個別のUSE Flagsは設定できません。またVIDEO_CARDSやINPUT_DEVICEなども選択できないので、巨大なパッケージをインストーラから入れるのはちょっと困難な気がします。
- カーネルはLiveDVDからコピーして利用しますので、設定は事実上存在しません。
インストール完了!!
そんな感じでインストール完了後のGentoo Linuxの様子です。make.confはほぼ空っぽ、syslogとcronは入っていますが起動していません。ネットワークはbusyboxのDHCPクライアント機能で動作しています。
起動してネットワークに繋がっていればなんとでもできるのがGentooですので、後はお好み次第です!!
おまけ。tinderboxからバイナリパッケージを取得して環境を作ってみた。
#gentooinstallbattleのレギュレーションに従うと、net-misc/mikutterでつぶやかないとGentooのインストールは完了しません。パフォーマンスに劣るVirtualBox上で手早くemergeを進めるために、バイナリパッケージ主体で環境を作ってみました。
# /etc/make.confに次のように書きます。 # amd64の場合。x86の場合はURIの最後がx86になります PORTAGE_BINHOST="http://tinderbox.dev.gentoo.org/default-linux/amd64"
あとは、emerge --getbinpkgonlyで必要なパッケージを揃えて行きます。バイナリパッケージをemergeすると当然のことながらUSE Flagsは調整できませんし、ときどきパッケージごとのバージョンミスマッチがあったりしていやんな感じです。具体的にはxorg-serverとx11-drivers/*にバージョンミスマッチがあってドライバを作り直す必要がありましたし、いくつかのパッケージはpython:2.6に依存していたのでそれも普通にソースからemergeする必要がありました。
結果どれくらい素早くインストールが完了したかというと……たぶん、試行錯誤した時間も考慮に入れると、普通にコンパイルしながら最小構成でmikutterを動かせるようになるまでの時間とたいして変わらなかった気もしますね。