更新履歴と目次
更新履歴
2010-03-03ページを公開しました.
このページは FreeBSD の ports を portupgrade を利用して更新,管理するための Tips をまとめたページです. portupgrade を使いこなすには ports の管理そのものに関する知識が必須です. 前項の「ports の管理」もあわせて参照して下さい.
portupgrade は FreeBSD の ports からインストールしたソフトウェアを更新したり, 依存関係を修正する等の作業を部分的に自動化するためのツールです. なお, portupgrade は Ruby を利用して実装されています.
まず,portupgrade をインストールしないことには話が進みません. ここではバイナリパッケージを利用してインストールを行います.
# pkg_add -r portupgrade # rehash
同時に Ruby がインストールされることに注意してください. なお, ports からインストールする場合はports-mgmt/portupgradeか sysutils/portupgrade (古い ports ツリーの場合) からインストールしてください.
portupgrade の設定ファイルは既定では/usr/local/etc/pkgtools.conf です.いくつかの設定を行っておきます. まず,パッケージの取得先を変更します.
ENV['PACKAGEROOT'] = 'ftp://ftp.jp.FreeBSD.org'
日本の FTP サーバーはいくつかありますが, 日本にある FreeBSD 関連のサイト 等を参考に相手先の負荷状況に応じて記述しましょう. 続いて「portsを更新する」 等で多国語関連の ports の更新を除外している場合は次のように記述します.
IGNORE_CATEGORIES = [ 'arabic', 'chinese', 'french', 'german', 'hebrew', 'hungarian', 'korean', 'polish', 'portuguese', 'russian', 'ukrainian', 'vietnamese']
最後に 「設定ファイルmake.confをカスタマイズする」 でバイナリパッケージの作成先のパスを変更している場合は以下のように記述します.
ENV['PACKAGES'] ||= 'somewhere'
portupgrade が FTP から取得したパッケージやバックアップとして作成したパッケージはここに保存されますので, 容量に余裕のあるディスク領域を指定しましょう. pkgtools.confに記述すべき設定は他にもあるのですが, この程度の設定であれば,とりあえずは無害であると言えます.
ここでは portupgrade の引数で良く知られているものについて記述します. なお, portupgrade の更新の判断は全て現在の ports ツリーに基づいて行なわれます.
portupgrade -a
この引数はインストールされている全ての port を全自動で最新版に更新します. これほど恐ろしく,かつ使い途の乏しい引数はありませんので,もしも利用するのであれば十分に注意してください.
portupgrade -b
portupgrade が port をインストールする前に構築したバックアップパッケージを削除せずに保持します. この引数を利用しない場合,バックアップはインストールに成功した時点で削除されますが, インストールが成功することと更新した port が正常動作することは別問題ですので, その差し戻しのための保険として利用します.
portupgrade -n
この引数を組み合わせた場合, portupgrade は実際のインストール作業を行ないません. 更新作業の内容を事前に把握し,検討を行なうために利用します. portupgrade の利用に慣れるまではこの方法で動作を良く把握すると良いでしょう.
portupgrade -p
インストール作業のついでにパッケージを作成します. ディスク領域に余裕が無い場合を除けば,有用な引数と言えます. 構築したバイナリパッケージを再利用する場合に利用します.
portupgrade -w
既定の動作における更新作業の前のmake cleanの実行を抑制します. 何らかの理由で中断したビルド作業を途中からやり直す場合などに利用します. 逆に更新作業の後のmake cleanの実行の抑制は-Wという引数を用います.
portupgrade -N
新規インストールを行ないます. この引数は port 名の他に origin (port の出所に対応するツリー) を取ることができます.例えば Firefox などバージョンごとにツリーが分かれている場合に利用します.
# portupgrade -N firefox
# portupgrade -N www/firefox
# portupgrade -N www/firefox35
上段のように指定した場合は対話的にバージョンの指定を行ないますが, 中段の場合は 2010 年現在の最新安定版である 3.6 系が, 下段の場合は 3.5 系がインストールされます.
portupgrade -P
更新作業にビルド済みのバイナリパッケージを利用します. FTP に存在するバイナリパッケージはリリース時の版しかありませんが, 別の計算機で構築したものを共有する場合等,より新しいパッケージが利用可能な場合に用います. バイナリパッケージの探索はpkgtools.confの記述に基づいて行なわれます. 引数-PPを用いた場合は取得可能なパッケージのみを利用します. 更新作業に ports のビルドを用いたくない場合に使用します.
portupgrade -r
依存関係を下にたどって更新作業を行ないます. 引数で与えたsomepackageに関して, somepackageを必要とする (Required by) port , すなわち,pkg_info -R somepackageの結果が更新対象となります. pkg_infoとの引数の対応に注意してください.
portupgrade -R
依存関係を上にたどって更新作業を行ないます. 引数で与えたsomepackageに関して, somepackageが依存する (Depends on) port , すなわち,pkg_info -r somepackageの結果が更新対象となります. pkg_infoとの引数の対応に注意してください. パッケージによっては大量の再インストール,再ビルドが必要になることがありますので, この引数の指定には十分な注意が必要となります.
portupgrade と同時にインストールされる便利なコマンドについて記述します. pkg_fetch ネットワーク経由でパッケージを取得するコマンドです. 次のように引数-Rをつけて実行することで指定したパッケージの依存関係を再帰的にたどりながらパッケージを取得します. ここで@は自動的にバージョン番号に置換されます.
# pkg_fetch -R somepackage@
前述の通り,格納先は設定ファイルpkgtools.confに記述します. このコマンドはバイナリパッケージを取得するためだけに利用します. インストールを伴わないので,オフラインで利用する別の計算機のためのパッケージの取得などに有用です. pkgdb portupgrade が利用するパッケージデータベースを管理するためのコマンドです. インストール済みの port の依存関係の修正にも利用できます. 後述する port の名称変更等が原因で依存関係を修正する場合,多くの場合は次のようにします.
# pkgdb -auF
引数-uはデータベースの更新, -Fはデータベースの依存関係の修正, -aは-Fとあわせて使用した場合,自動処理を行なうことを意味します. 手動で依存関係を修正する場合は-Fを単独で利用します. なお,部分的に portupgrade によらない port の更新を行なった場合もこのコマンドを利用します.
portsclean
port のインストールやビルドに利用した一時ファイルや配布ファイルを削除します. portsclean -C /usr/ports以下の作業ディレクトリworkを探索して削除します. portsclean -P 現在の ports ツリーと比較して最新版でないバイナリパッケージを探索して削除します. -PPを指定した場合は全てのパッケージを削除します. 何らか事情で最新でないパッケージが必要な場合は利用してはなりません.
portsclean -D
現在の ports ツリーから参照されない配布ファイルを探索して削除します. 引数-Pと同じく最新でない配布ファイルが必要な場合は利用してはなりません. portsclean -L 二重に存在する,または出所不明の共有ライブラリを削除します.安易な利用は推奨されません. portversion インストール済みの port のバージョンを ports ツリーと調査比較して状態を出力します. インストール済みの port より ports ツリーの方が新しい port を調べるには以下のようにします.
# portversion -vl '<'
あらかじめデータベースを構築しておくため,システム標準のpkg_versionより高速であることが多いようです. portinstall 新規に port をインストールします.portupgrade -Nとしても同じなので利用の機会はあまり無いかも知れません.
portupgrade の実行例
続いて, portupgrade のマニュアルからいくつかの事例を抜き出して解説します. ある port を必要とする port を対話的に全て更新する# portupgrade -ri somepackage 前述のようにsomepackageを必要とする全ての port を対象として更新作業を行ないます. ただし,引数-iによって処理を対話的に行なうことができます.
ある port の名称が変更されたので更新しつつ依存関係を修正する# portupgrade -rfo somepackage renamedpackage
somepackageがrenamedpackageに名称変更された場合に利用します. この方法では引数-oによってsomepackageをrenamedpackageに置き換え, さらにsomepackageを必要としていた port (引数-r)を強制的に (引数-f) で更新します. ある port が依存する port を全て更新してパッケージを作る# portupgrade -Rp somepackage somepackageが依存する port を全て更新し, インストールした port のパッケージを作成します. 依存関係を遡りすぎないよう注意してください. ある port をパッケージ限定でインストールする
# portupgrade -NPP somepackage
somepackageを新規インストールします. ただし,現在のツリーに対応するバージョンのパッケージが見つからない場合は, 見つかった中で最も新しいパッケージからインストールを行ない, port のビルド作業は行ないません.
引数-oや引数-fなど解説していないものをいくつか挙げましたが, -fによる強制は 「『更新しない』という選択」 で記述するHOLD_PKGSの設定より優先しますので特に注意が必要です.
ここまでで, portupgrade ,そして同時にインストールされるツールの大まかな利用方法を記述しました. 既述の通り,重要なのはここから先ですので十分に注意してください. port の更新で重要となる依存関係に関する解説は次節で記述します.
FreeBSD の port を更新するには,まず,何らかの方法で ports のツリーを更新する必要があります. 通常は csup や portsnap を利用します. 前項「portsを更新する」を参考に, ports のツリーを更新しておいてください.
port を更新するための手順は主に次のようになります.
重要なのはとにかく「前準備」の部分であって,実際の作業でないことに注意してください. FreeBSD の日曜管理者を忙殺する原因のほとんどは port の更新がらみであるといえます. 地獄を作り出すのは常に「いい加減な前準備」や「安易な計画」であることを肝に銘じてください.
まず,port のバージョン比較の結果をファイルに書き出しておきます.
# portversion -vl '<' > /root/ports.info
FreeBSD の port のバージョンは概ね以下のように記述されます.
foo-$PORTVERTION$_$PORTREVISION,$PORTEPOCH
例えば,fooというパッケージのfoo-1.23_4,5というバージョン番号の場合, $PORTVERTIONが1.23, $PORTREVISIONが4, $PORTEPOCHが5となります. この中でソフトウェアの開発元のバージョン番号は$PORTVERTION に対応することが多いため, $PORTREVISIONと$PORTEPOCHは FreeBSD の port としての版を指すと言えます. したがって,利用者として更新が必要となるのは主に$PORTVERTIONが新しくなる更新です.
バージョン番号を比較して更新する port を決定したら, 前項「転ばぬ先の杖」を参考に更新内容を把握します. 特に,/usr/ports/UPDATINGには確実に目を通しましょう. 場合によっては更新に特殊な手続きが必要になることがあるためです (後述する「『sweeping change』と『祭』」がこれにあたります). また, port のカテゴリ移動や名称変更,別の port への統廃合等は/usr/ports/MOVEDに記述され, このような場合は依存関係を手動で修正しなければならないこともあります.
更新したい port を決定したら,次はその依存関係を調査します. ここで,「依存関係」と呼ばれるものは大まかに言って三種類存在します. FreeBSD の port における「依存関係」はMakefileにおける以下の記述を指します.
BUILD_DEPENDS
port のビルド自体に必要となる依存関係です. 共有ライブラリなどが指定されることが多いようです. 以下の記述はバージョン番号付きの依存関係です. BUILD_DEPENDS= var>=1.2:${PORTSDIR}/foo/var この場合,当該 port のビルドにはvarという port の1.2以上の版が必要であり, 存在しない場合は ports ツリーのfoo/varよりインストールせよ,という意味です. 依存関係の中では最も厳しい条件であり, 依存関係に指定された port が条件に合わないと多くの場合はビルド自体が失敗します. したがって,こうした場合は依存関係にある port を先に更新しておかねばなりません.
LIB_DEPENDS
port が必要とするライブラリに関する依存関係です. 以下の記述はバージョン番号付きの依存関係です.
LIB_DEPENDS= var.1:${PORTSDIR}/foo/var
読み方はBUILD_DEPENDSとほぼ同じですが, バージョン番号は port のものではなく,libvar.so.1といった共有ライブラリのものであることに注意してください. このバージョン番号が異なる場合には事前に共有ライブラリを更新せねばなりません. ただし,仮にバージョンが同じでも共有ライブラリの仕様が変わって互換性が損なわれている場合がありますので, 良く調べた上で依存関係にある port を更新することが推奨されます.
RUN_DEPENDS
port が実行時に必要とするファイルやコマンドに関する依存関係です. 三種類の依存関係の中では最も単純で,バージョン指定がなされることも稀です.
いま,ソフトウェアfooが共有ライブラリlibvarに BUILD_DEPENDSないし,LIB_DEPENDSで依存しており, libvarもまた更新可能である場合を考えます. この場合, portupgrade は次のように実行します.
# portupgrade -R foo
こうすることで多くの場合はfooの前にlibvarの更新が行なわれ, 改めてlibvarに依存するfooの更新が行なわれます. 逆に次のようにすることもできます.
# portupgrade -r libvar
この記述では,まずlibvarの更新が行なわれ, そのあとでlibvarを必要とするfooの更新が行なわれます.
fooと共有ライブラリlibvarの関係だけに着目すれば両者は同じ動作に見えますが, 実際の場合,両者は全く異なる結果を生むことがほとんどです. 結論から言えば,共有ライブラリlibvarの依存関係がまだ完全には明らかでないからです. 以下の場合が考えられます.
この場合に引数-Rでfooを更新した場合, libvarのバージョンが変わったことでfoo2が動作しなくなる恐れがあります. したがって,この場合は引数-rでlibvarを更新することで, libvarを必要とするfooとfoo2の両方を更新できます. しかしながら,libvarが多量の port から必要とされている場合, 更新範囲が事前に予測できなくなるかも知れません.
このような場合に引数-Rでfooを更新した場合, fooから遡った依存先であるlibvarの更新でさらに多量の依存関係を解決せねばなりません. 具体的にはlibvarの依存する port 全てに対して再ビルド,更新が行なわれます. 計算機の資源は有限ですから,多量の port の再インストールは避けたいというのが本音です.
最悪なのがlibvarがlibvar2に依存しているとして, libvar2がソフトウェアfoo3から必要とされている場合です. 依存関係を上だけに見てゆく限りfooからfoo3は見えませんので, この種の問題は基本的に管理者が面倒を見なければなりません. 前述の場合と同様に下手をすると更新範囲が際限無く広がる恐れがあります.
まとめると-R引数や-r引数による依存関係の自動解決には限界があります. したがって,実行前に依存関係と影響範囲を管理者が自分で考えて,できるだけ影響範囲が小さくなるような更新計画を立案する必要があります. いっそのこと,portupgrade -aとしたいところですが, そんなお花畑な選択の前に我々が FreeBSD を利用するのは何らかの目的のためであって, ports のお守りをするためではない という現実に立ち返る必要があります. いちいち全 port の再ビルドを行なっていては, 余程高性能な計算機でない限りは日常のほとんどを port の更新に忙殺されている, という意味不明な状況になりかねません (引数-aが使い途に乏しいというのはこの意味です).
次節では本節で扱ったような影響範囲の大きな port の更新について記述します.
前節でport を更新する場合にそれぞれの port の依存関係から更新範囲が際限無く広がる恐れがある点を指摘しました. 本節ではこの問題について実例を挙げて説明します. FreeBSD の ports システムにおける「影響範囲が予測できない更新」をsweeping changeと言います. 更新作業がこの種の port に引っ掛かると大変な手間が必要となることがあります. 困ったことに,この種の更新は定期的に発生しています.以下がそのような port の一例です. これらは俗に「Perl 祭」や「gettext 祭」と呼ばれます.
Perl (lang/perl5.10,lang/perl5.8等)
言わずと知れたスクリプト言語の処理系です. 定期的に発生する地雷です. 名称がp5-で始まる port は Perl 5 系に依存するソフトウェアです. 困ったことに,これらのインストール先のパスに Perl のバージョン番号が含まれているため, マイナーバージョンの変更であっても Perl を更新する場合は依存する全ての port を更新する必要があります. 大抵の場合は/usr/ports/UPDATINGでアナウンスがあり, perl-after-upgradeというスクリプトを実行するように指示がありますが, Perl はかなり更新が面倒な部類に入ります. さらに恐ろしいのは Perl 地雷は他の地雷に比べればかわいい部類である,という点です.
GNU gettext (devel/gettext)
GNU gettext というソフトウェアの国際化に関する共有ライブラリです. sweeping change の代表格のような地雷です. ほぼ全ての port が何らかの形で依存しています. gettext の更新を行なうくらいなら全ての port を再ビルド,再インストールしたほうが良いくらいです. /usr/ports/UPDATINGに書いてある内容もこれと大して変わりません. 著者はこの port の更新は絶対に行ないません.
PNG, TIFF(graphics/png,graphics/tiff等)
それぞれ PNG,TIFF 形式の画像を扱うための共有ライブラリです. PNG については 2010 年の春に共有ライブラリのバージョン番号が更新され, sweeping change が発生しました. gettext と同じく PNG を必要とする全ての port の再インストールが必要です.
Xorg (x11/xorg)
X Window のライブラリおよびサーバー類,アプリケーション類です. 細々としたライブラリやアプリケーションの集合体ですが, それぞれが密な網目状の依存関係で結合しています. 2007 年の初夏に Xorg のバージョンが 7.2 に更新されたときは直前に ports ツリーにPRE_XORG_7というタグが打たれるなどの特別措置が取られました. /usr/ports/UPDATINGでは 「ようこそ!恐い物知らず達よ!」などという冗談のような文句 (原文は「Welcome, fearless user! You are about to embark upon a mystical journey to the world of X.Org 7.2.」)で更新がアナウンスされ, 複雑怪奇な手順が説明されました. こちらも自動的な更新はほぼ不可能です.
Linux 互換機能 (emulators/linux_base-f10等)
Linux 互換関連の port は全てこの port に依存しています. 影響範囲の大きさも然る事ながら,この port は FreeBSD のカーネルの機能自体に密に結合しており, 最新安定版,開発版以外のカーネルでは動作しなかったり, そもそもインストール自体が不可能なことがあります. この port の更新もほぼ不可能です.
上述したような著名なものでなくとも/usr/ports/MOVED に記述されるような port 名の変更をともなう更新で依存関係の解決を portupgrade まかせにするのは危険です. 更新に失敗すると名称変更前と名称変更後のツリーに対応する port が両方インストールされたり, port が二重にインストールされ「Duplicated Origin」等のエラーが発生することがあります.
まとめると portsnap や csup で妙に大量の更新が行なわれた場合は警戒が必要になります. 特に,/usr/ports/UPDATINGが更新された場合は必ず目を通す癖を付けましょう. portupgrade を実行するのはそのあとで十分です.
依存関係を含む port の更新はとにかく面倒です. セキュリティ上の脆弱性が無いならば「更新しない」こともまたひとつの選択です. portupgrade には特定の port を更新の対象外にする設定が存在します. この設定は pkgtools.confで行ないます. 更新したくない port はpkgtools.conf以下の記述に追加 する形で記述します.
HOLD_PKGS = [ 'bsdpan-*', ]
前述の sweeping changes にかかる port はここに追加しても良いかもしれません.
これまでも散々書いてきたことですが, 面倒ごとを抱え込まないためには必要のない更新は行なわないことが重要です.
「ports ツリーを更新したらコンパイルエラーが…」であるとか, 「port が無くなった」, さらには「依存関係が壊れた」等の不具合の原因のほとんどは依存関係を見誤り,不適切な更新範囲で作業を実施したことです. The freebsd-ports Archivesや Current FreeBSD problem reportsには「更新したら不具合が」という報告さえあります. 更新作業を行うのであれば計画は慎重に立案しましょう.
このページの結論は…
という素人には全く参考にならない手順となります.
port の更新で依存関係の修正を間違えたときに発生しうる災害の一例について記述します. ここでは,共有ライブラリlibhuga1を必要とするソフトウェアhoge1とhoge2 がインストールされているものとします.リストの矢印は依存関係です. なお,更新前のlibhuga1には開発版としてlibhuga-develが存在するものとします. 簡単のためにlibhuga1の依存は無いものとします.
更新前の ports ツリー
更新後の ports ツリー
いま, ports のツリーを更新したことで libhuga1の開発版のlibhuga-develが安定版となり, libhuga2なる新たな名前を与えられ,hoge1とhoge2双方のバージョンの更新と合わせて依存関係も更新されたとします. ここでは,バージョン指定付きのLIB_DEPENDSが与えられたとします.
LIB_DEPENDS= huga>=2:huga
hoge1の更新だけに興味があるとして,以下のように実行すると何が起こるでしょうか.
# portupgrade -R hoge1
以下は最悪の例であることに注意して下さい (運が良ければ更新は成功します).
port が「共存不可」であることはMakefileのCONFLICTという記述で確認できます. しかしながら, portupgrade は基本的にFORCE_PKG_REGISTERでインストールを行うため, CONFLICTを無視してインストールを行うことがほとんどです. この中途半端な更新が行われた結果,port のインストール状態は次のようになります.
この場合,最初の更新計画においてhoge1とhoge2 が必要とするlibhugaが名称変更されていることを考慮し, portupgrade を-rfo引数で実行すべきであったと結論できます.
事後にこの問題を修復するにはhoge2とlibhuga1を強制的に削除して, 新たなツリーのhoge2を再インストールするなどの方法が考えられます. 余談になりますが,これで解決できるのはあくまでもport の依存関係であることに注意してください. 更新したhoge1とhoge2が正常動作するかは別問題ですので, きちんと動作確認をしましょう.
port のビルドを繰り返すとBUILD_DEPENDS等の指定によって, ビルド時にのみ必要となるパッケージがインストールされることが多くなります. この種の「必要とされない」パッケージを探すには,例えば次のようなシェルスクリプトを利用することが考えられます.
#!/bin/sh plist=`pkg_info | awk '{print $1}'` for pname in $plist ; do result=`pkg_info -R $pname | grep -v Information` if [ -z "$result" ] ; then echo $pname fi done
リストされたパッケージの中で不要と判断されたものはアンインストールできます. ただし,これはパッケージ管理システムによって Required By の指定がなされていないものをリストするスクリプトであって, 不要なパッケージを探すものではないことに注意してください. 利用者が必要でインストールたパッケージで他から Required By の指定がないものが含まれるだけでなく, パッケージ管理データベースの破損などによって本来必要な依存関係が記述されない場合があるためです. したがって,本当に不要かどうかは適切な判断を要することに注意してください.
また,このような Required By の指定がないパッケージは更新が比較的容易であるため, 更新可能なパッケージを探す場合にも利用できます. ただし,元になった port のバージョン指定付きのLIB_DEPENDSなどにより, 別のパッケージの更新を必要とする場合は更新範囲が拡大する恐れがあります.
ソフトウェアの開発元から入手した配布ファイルから得られるconfigureスクリプトを利用することで, FreeBSD の ports システムを利用せずにソフトウェアをインストールする方法を俗に「野良ビルド」と呼称する向きがあるようです. この方法が推奨されるのは主に以下の理由によるようです.
本件に関する著者の見解は「分かっているなら御自由に」というものです. FreeBSD の ports システムにはソフトウェアを FreeBSD で利用するためのパッチ等が含まれます. この種の改変の内容とconfigureの動作の双方を理解し,その上で ports のパッチが不要であると考えるならばそれで良いはずです. しかしながら, ports を利用する場合,以下のような利点があるのも事実です.
ports を利用する場合,ファイルのインストール先は概ね/usr/local/以下になります. 設定ファイルのサンプルと既定の参照先は/usr/local/etc/内, ドキュメントは/usr/local/share/doc/と言った具合いです. そして,下の二つはソフトウェアをアンインストールする際に役に立ちます. インストールするファイルのリストが正しく記述されているかどうかを調べるテスト (TinderBox Test のテスト項目のひとつ) はかなり厳格に行われているからです. したがって,基本方針としては以下のようになります.
システムの状態と目的に従って,種々の手段を比較検討し最適な判断を自身で下すべき
必要ならば ports にパッチを当てるなど,FreeBSD の ports の枠組み内で何とかする. 試行錯誤でシステムを止めてしまったりするかも知れないが, アンインストール時にはきれいさっぱり.
知識がないなら他者への屈従を強いられるのは当然で ports をそのまま利用すべき. ports に不満があっても我慢するしかない. configureを用いるならば, それがどこに何をインストールするように設定するか程度は読めるようになってからにすべきです.
聞く耳をもたぬ方にはこのページの記述は全く役に立ちません.自己責任でどうぞ. ただし,そうしたノウハウを Web 上に公開してくださると著者としては大変嬉しく思います.
ちなみに,著者は「日曜管理者」です. 日常的に ports のMakefileを読むことで知識を付け,必要に応じて ports のパッチを書くことが最も楽であると考えています.