portsを書こう

概要

FreeBSD には ports というシステムがあります。活用されている人も多いで しょう。しかし、 ports を書いている層がどれくらいいるかというと……あ まり多くはないのではないかと思います。確かに、ちゃんとした ports を一 から書き上げるのには、それなりの知識と学習が必要です(たいしたことない といえばたいしたことない)。ただし、たとえばバージョンを上げる程度のこ とであれば、特にそれほど大きな問題もないはずです。本稿では、 ports の ことを全然知らないという人が、ひとまず簡単なバージョン変更程度の send-pr が出来るようになることを目指します。そのことによって、メンテナ がサボっていたりいろんな理由によって、本家のバージョンが上がっているの にパッケージのバージョンがいつまでたっても上がらない、等の不満が解消さ れるでしょう。

はじめに

本稿では、 FreeBSD はある程度は使っているということを前提としてます。 したがってここでは ports とは何かとか、どうやって「使う」のか、という ことはくだくだと説明しません。また、それについては『徹底入門』等の良書 があるので書籍を参照すると良いでしょう。

本稿を読む上で理解してほしいのはだいたい次のことです。

  1. ports とは FreeBSD 上でパッケージをビルドして管理するシステムである
  2. make というコマンドを使う。make、make install、make deinstall くらいは知っている
  3. portupgrade というのがある

ports の構成を見る

おそらく大勢の人が御存知のように、 ports は /usr/ports というディレク トリの下に存在しています。たとえば筆者がメンテナをやっている scim-skk というソフトウェアの ports は /usr/ports/japanese/scim-skk となります。 ひとまずこのディレクトリの中身を見てみましょう。

ls -l するとこうなりますね。

-rw-r--r--  1 root  wheel  1399 11  1 22:08 Makefile
-rw-r--r--  1 root  wheel   101 11  1 12:25 distinfo
drwxr-xr-x  2 root  wheel   512 10 18 15:01 files
-rw-r--r--  1 root  wheel   105  7 31 01:49 pkg-descr
-rw-r--r--  1 root  wheel   395  7 31 01:49 pkg-message
-rw-r--r--  1 root  wheel   315  7 31 01:49 pkg-plist

それぞれ意味があります。

Makefile
make コマンドの動作を制御するためのファイルだと考えてください。主にこのファイルをいじります
distinfo
そのパッケージで使用するファイルの情報が格納されています
files
各種ファイル(主にパッチ)が収められているディレクトリです
pkg-descr
そのパッケージの情報が保存されています
pkg-message
そのパッケージをインストールした時に表示されるメッセージなどが保存されています
pkg-plist
そのパッケージに属するファイルのリストです

このほかに work というディレクトリがあることがあります。これは ports で make した際に出来た作業ディレクトリで、 make clean すると消えます。 放置していてもファイル領域の圧迫以外には特に問題はありませんが。

ほかにもいくつかのファイルが場合がありますが、それはその ports により ます。また、たいていの ports には pkg-message はありません。

ここからの作業は、基本的には「Makefileをいじる」「distinfoを更新する」 「必要ならpkg-plistを更新する」「上手く動くか試す」ということになりま す。

いじる前に

実はいじる前にやっておくことがあります。ここではとりあえず、 scim-skk の更新をしてみます。何が必要かというと、変更前のもののバックアップを取っ ておく必要があるのです。これは、最終的に変更を報告する時に「どこが変更 されたか」を記録するために必要だからです。

というわけで、

# cd /usr/ports/japanese
# cp -r scim-skk{,.orig}

などとして、バックアップを取っておきましょう。

Makefile を見てみる

では変更を試みるわけですが、まずは Makefile を見てみるところから始めま しょう。

# New ports collection makefile for:    ja-scim-skk
# Date created:		6 Apr 2005
# Whom:			Jun Mukai <mukai@jmuk.org>
#
# $FreeBSD: ports/japanese/scim-skk/Makefile,v 1.5 2005/08/01 08:08:27 nork Exp $
#

PORTNAME=	scim-skk
PORTVERSION=	0.3.0
PORTREVISION=	0
CATEGORIES=	japanese
MASTER_SITES=	${MASTER_SITE_SOURCEFORGE_JP}
MASTER_SITE_SUBDIR=	scim-imengine/15351

MAINTAINER=	mukai@jmuk.org
COMMENT=	SCIM IMEngine module like SKK

BUILD_DEPENDS=	scim:${PORTSDIR}/textproc/scim
RUN_DEPENDS=	${BUILD_DEPENDS}

USE_X_PREFIX=	yes
USE_ICONV=	yes
USE_GMAKE=	yes
USE_REINPLACE=	yes
USE_LIBTOOL_VER=15

CONFIGURE_ENV=	PTHREAD_CFLAGS="${PTHREAD_CFLAGS}" \
		PTHREAD_LIBS="${PTHREAD_LIBS}"

.include <bsd.port.pre.mk>

.if ${OSVERSION} < 500035
BUILD_DEPENDS+=	${LOCALBASE}/lib/libstlport_gcc.so:${PORTSDIR}/devel/stlport
RUN_DEPENDS+=	${LOCALBASE}/lib/libstlport_gcc.so:${PORTSDIR}/devel/stlport
CONFIGURE_ENV+=	CPPFLAGS="-I${LOCALBASE}/include -I${LOCALBASE}/include/stlport" \
		LDFLAGS="-L${LOCALBASE}/lib -lstlport_gcc ${PTHREAD_LIBS}"
.else
CONFIGURE_ENV+=	CPPFLAGS="-I${LOCALBASE}/include -D__STDC_ISO_10646__" \
		LDFLAGS="-L${LOCALBASE}/lib"
.endif

post-patch:
	@${REINPLACE_CMD} "s|LOCALBASE|${LOCALBASE}|" ${WRKSRC}/src/scim_skk_prefs.h

post-install:
	@${CAT} ${PKGMESSAGE}
	@${ECHO}
	@${ECHO} To display this message again, type \`pkg_info -D ${PKGNAME}\'
	@${ECHO}

.include <bsd.port.post.mk>

はい、けっこうややこしいですね。これを怯まずに内容の理解を試みることの できる人は本稿の対象ではありません。恐れずに porter's handbook を読むとよいかと思います。

で、けっこう長い上にややっこしいのですが、実は細々とした設定の記述だと 考えれば、さほど理解は困難ではありません。たとえば USE_X_PREFIX=yes な どは、何か知らないがX11を使うようです。また、 ports の Makefile では、 空行で区切られた区分ごとに役割がけっこう決められています。たいていの場 合、あまりややこしいことはしなくても問題ありません。

しかも、バージョンの変更程度で書換える必要があるのは、実は比較的冒頭に 近いここのセクション程度であることが多いのです。

PORTNAME=	scim-skk
PORTVERSION=	0.3.0
PORTREVISION=	0
CATEGORIES=	japanese
MASTER_SITES=	${MASTER_SITE_SOURCEFORGE_JP}
MASTER_SITE_SUBDIR=	scim-imengine/15351

これくらいなら、だいたいわかるんじゃないでしょうか。 PORTNAME はその ports の名前だし、 PORTVERSION はそのバージョン、 CATEGORIES はカテゴ リです。実際その通りで、簡単な port なら PORTVERSION を書き直せば動き ます。次のように。

PORTNAME=	scim-skk
PORTVERSION=	0.4.0    # ←ここが変わった
PORTREVISION=	0
CATEGORIES=	japanese
MASTER_SITES=	${MASTER_SITE_SOURCEFORGE_JP}
MASTER_SITE_SUBDIR=	scim-imengine/15351

ただし、 MASTER_SITES や、この ports にはありませんが、 DISTNAME といっ た名前の設定には注意をしなければいけません。

MASTER_SITES は、ファイルをどこからダウンロードするか、ということを設 定するものです。 ports では自動的にファイルをダウンロードしますが、そ の場所を指定するわけです。他の ports を見てもらえればわかるように、こ こには普通に URL を書けばそれで問題ありません。が、この scim-skk のよ うに sourceforge で配布されているソフトウェアにはそれ専用の設定があり、 上記のように MASTER_SITE_SOURCEFORGE_JP を使うことであらかじめ設定され ているところからダウンロードできます。ただし、 sourceforge.jp にはちょっ と面倒なところがあり、ただ共通の設定だけでは上手く行きません。というの は、サブディレクトリの 15351 というのが見えると思いますが、ここの数値 がリリースごとに変わるという、ちょっと出来のよろしくない仕様があるため です。これは自分でそのプロジェクトのページを見て修正する必要があるでしょう。

PORTNAME=	scim-skk
PORTVERSION=	0.4.0
PORTREVISION=	0
CATEGORIES=	japanese
MASTER_SITES=	${MASTER_SITE_SOURCEFORGE_JP}
MASTER_SITE_SUBDIR=	scim-imengine/17186  # ←ここも変わった

それと、 ports のためにダウンロードするファイルは、基本的には

${PORTNAME}-${PORTVERSION}.tar.gz

という形式になります(この例なら scim-skk-0.4.0.tar.gz になる)。しかし、 時々このフォーマットに沿わないものもあります。そういう場合には DISTFILE 等の設定によって変更することができます。この場合も、バージョ ンが変わってもダウンロードしようとするファイルが上手く行かなくてはまる ことがあります。充分に注意してください。

distinfo を更新する

Makefile を書き直せば、基本的には ports の変更は終了です。が、 distinfo を変更しないといけません。 distinfo とはなんでしょうか。中身 を見ると、

MD5 (scim-skk-0.3.0.tar.gz) = 8ff1eebd49f62a5d19d21513d884402c
SIZE (scim-skk-0.3.0.tar.gz) = 531688

などとなっています。このファイルでは、ダウンロードする個別のファイルの MD5 値とファイルサイズを決めています。 MD5 というのは……という説明は ほかのドキュメントに譲ることにします(説明が面倒くさいので)。何かしらの アルゴリズムで、ファイルごとに値を計算するのだと理解してください。ファ イルが変更されると値も変わります。ですから、たとえば悪意を持ってバック ドアつきに変更されたファイルを配布しようとした人がいてうっかりそれをダ ウンロードしてしまったとしても、 MD5 値が変更されているのでチェックで きるという仕組みです。 MD5 値が偶然に一致する(衝突という) こともあるの ですが、 distinfo にはファイルのサイズも記録されていて二重にチェックし ているので、それなりには安全です。

さて、このファイルを更新するにはどうすればいいでしょうか。手で書くのは さすがに面倒ですね。これは自動化する手段があります。が、そのためにはビ ルドするのに必要なファイルが手元になければなりません。自分で手でダウン ロードしても良いですし、 ports の仕組みを使って自動的にダウンロードし ても良いでしょう。

自分でダウンロードした場合は、そのファイルを /usr/ports/distfiles 以下 に置きます。ものによってはさらにそのサブディレクトリに入れることもあり ます(たとえば ruby 関係は /usr/ports/distfiles/ruby の下に置きます)。

ports の仕組みを使ってダウンロードする場合には、次のようにします。

# make fetch NO_CHECKSUM=yes

ただし、通常のように make fetch をすれば、当然のように distinfo をチェッ クして「そんなファイルは distinfo にありません」というエラーを吐きます。 当然ですね。 distinfo はこれから更新するんですから。なので、一時的に distinfo のチェックを抑制する NO_CHECKSUM=yes というオプションをかけま す。

というわけで、どちらの場合にせよ、 distinfo に記録する前に、自分がダウ ンロードしたソフトウェアが正しいものであるかをチェックしなければならな いことに注意してください。最近のちゃんとしたソフトウェアは、ダウ ンロードするファイルの MD5 値(や他の同様なハッシュ値)が記載されている のが普通です。確認は怠らないようにしましょう。

さて、ともかく /usr/ports/distfiles あたりにファイルを置いたとしましょ う。こうなれば楽なもので、次のコマンドを実行します。

# make makesum

これで distinfo が更新されます。

MD5 (scim-skk-0.4.0.tar.gz) = 0d5ee7f39aef2b926e1a4907da00c0c9
SIZE (scim-skk-0.4.0.tar.gz) = 521969

ビルドしてみる

修正した結果として、正しく構成できているかを確かめないといけません。そ れには、実際にビルドしてみるのが良いでしょう。

# make 
# make deinstall
# make reinstall

で更新されます。実行中、あるいはインストール後の試用で特にエラーが発生 しなければ、問題がない可能性が高いです。

ここで問題があるとすれば、パッチが充てられなくなっていることが多いでしょ う。パッチとは何でしょうか。

いくつかのソフトウェアでは、そのままインストールするのが FreeBSD とし ては好ましくないので修正をかけることがあります。この修正はパッチと呼ば れていて、 UNIX 系の OS ではごくごく基本的なコマンドで修正(パッチをか けるとかパッチをあてると言われる)をすることができます。 ports の場合、 make patch コマンドを実行することで、あらかじめ用意しておいたパッチを 自動的に適用します(これは、通常のmakeでも実行されています)。

さて、このパッチは files 以下にあります。今回の scim-skk では問題は起 きなかったので見る必要はないのですが、後学のためにとりあえず見てみます。

# ls files
patch-src-scim_skk_prefs.h

files には、主にパッチ関係のファイルが入りますが、実際には他の目的のファ イルが入ることもあります。そこで、パッチ用のファイルは patch- という名 前がつけられています。 patchl- 系のファイルの名前のつけ方は2種類あり、 patch-aa などの謎のアルファベットのものと、この例のようにファイル名っ ぽいものがあります。 aa などのものは、順序が重視されているときに用いま す。つまり、まず aa のパッチを適用して、次が ab で……というような順序 を保証しつつパッチを適用するようなケースです。それに対して、順序が特に 重要でないなら、特定のファイルごとに修正をまとめ、ファイル名のパッチを つけた方がわかりやすいでしょう。これはまた歴史的な経緯でもあり、昔は aa 等がよく使われていましたが、最近はファイル名が多いように思います(…… が、筆者もそれほど詳しくは知りません)。

パッチファイルの書式等を理解しておく必要も、とりあえずはないのですが、 ともかくものは試しで見てみましょう。

- -- src/scim_skk_prefs.h.orig   Wed Jun 29 14:31:26 2005
+++ src/scim_skk_prefs.h        Sat Jul 30 19:26:45 2005
@@ -73,7 +73,7 @@
 #define SCIM_SKK_CONFIG_UPCASE_KEY_DEFAULT           "Control+u"
 #define SCIM_SKK_CONFIG_SELECTION_STYLE_DEFAULT      "Qwerty"

-#define SCIM_SKK_CONFIG_SYSDICT_DEFAULT          "/usr/share/skk/SKK-JISYO.L"
+#define SCIM_SKK_CONFIG_SYSDICT_DEFAULT          "LOCALBASE/share/skk/SKK-JISYO.L"
 #define SCIM_SKK_CONFIG_USERDICT_DEFAULT         ".skk-scim-jisyo"
 #define SCIM_SKK_CONFIG_CANDVEC_SIZE_DEFAULT      4
 #define SCIM_SKK_CONFIG_ANNOT_VIEW_DEFAULT    true

見てみれば、それほど難しくもないのではないでしょうか。このパッチであれ ば、 73 行目あたりが修正箇所で、 - が修正前で、その行を + の行に変更す る、ということになります。このパッチは、 skk のシステム辞書のデフォル トのパスを修正するものです。 linux 等では /usr/share/skk に置かれるこ とが多いので、 scim-skk はそのようなデフォルト設定で配布がされています。 一方、 FreeBSD ではほとんどの場合に /usr/local 等に配置されるわけです から、そのようにデフォルト設定を書換えているわけです。

さて、このようなパッチがあるわけですが、ソフトウェアのバージョンが上が ることでパッチのエラーが起こる原因としては、だいたい次のケースが一般的 です。

1. ファイルに大きな変更があった
ファイルに大きな変更があり、変更点の行数や前後の内容が変わったのでど こを修正したらよいかプログラムでは検出できない。
2. 変更が本家に取り入れられてパッチする必要がない
FreeBSD 用のローカルな変更でしたが、その問題がいろんな事情で解決され ることがあります。そうした場合、パッチする必要がなくなります。
3. ファイル名の変更/削除
パッチをあてるべきファイルの名前が変更されたり、削除されたりすること があります。

2の場合、もうパッチの必要がないので、単にその files/patch- のファイル を削除すれば問題ありません。 3 の場合も、パッチが必要なくなるケースが 多いように思います。問題は 1 のようにファイルに大きな変更があり、しか もまだパッチの必要がある場合です。

そのような場合は、実際のソースコードに手を入れ、パッチを作成しなければ なりませんが……本稿では読者にそのような技量を求めません。可能ならばそ こまでやると良いでしょうが、だめなら諦めるしかありません。

pkg-plist を見る

インストールするファイルのリストが pkg-plist です。バージョンアップ等 で変更されることはまずありません。しかし、まれにファイル構成が変わるこ とがあるので注意してください。

いちど make install したものを make deinstall して警告が出るようなら pkg-plist に問題がある証拠です。

ただし、警告が出なくても問題がある場合もあります。これは実際にインストー ルする際に何をインストールしたか、ちゃんとチェックして pkg-plist の内 容と突き合わせる、という地味な作業になります。しかし、大切なことでもあ ります。注意してください。 porter's handbook には、ちょっと裏技的に pkg-plist を自動生成する方法が提案されているのですが、その意味もわから ずにやり方だけ説明しても意味はないので、ここでは述べません。

ところで、 pkg-plist には、いくつかのオプションがあります。よくあるの が NOPORTSDOC=yes をつけるかつけないかでドキュメントをインストールする かどうか制御するものです。そのあたりもきちんとチェックした方が良いでしょ う。

portlint する

portlint というコマンドがあるので、 ports を弄る人はぜひともインストー ルしましょう。

# portinstall portlint

そして、自分が変更した ports のディレクトリで portlint コマンドを実行 してください。

# portlint
looks fine.

「looks fine.」つまり「良いようです」ということで、構文上の誤りがない か、変な書き方をしていないか、チェックできます。ほかの文言が出るような ら、なにか変な書き方をしているということです。エラーメッセージをよく読 み、修正を施してください。ただ、変更前からそのようなエラーメッセージが 出る ports も存在する可能性はありますが……。

portlint は万能ではなく、ある意味ではただの気休めにすぎません。ですか ら、絶対視することもありません。しかし、 looks fine. だったのが自分の 変更でおかしくなるようなことは避けるべきでしょう。

問題が発生したら

問題が発生することは、いつでもあります。その時、まずやるべきはその問題 の範囲を特定することです。そして、その問題が自分に解決可能かどうかを見 極めてください。

とはいっても、初心者の場合はたいてい問題は上手く解決できません。何が問 題なのかもよくわからない。そういうこともあります。そういう場合、諦めが 肝心です。

あるいは最近だと、日記やブログに書いておくと、物好きな人が発見して解決 してくれるかもしれません。 FreeBSD-ports-jp のMLにポストして相談してみ るというのも良いかもしれません。が、何が問題となっているのか、というこ とを理解せずにポストしても芳しい結果は得られないでしょう。

ports のバージョン修正程度で、大きな問題が発生することはあまりありませ ん。しかし、たとえば emacs などトリッキーな操作をするので面倒なことが 起きる可能性があります(emacs-20.x と 21.x と xemacs のそれぞれ用の ports を用意したりといったことがあるため)。 ruby18 と ruby18_r、perl、 などなど、規模の大きなものに依存した場合には、面倒が起きることもありま すので注意しましょう。

まあそうはいっても、たいていは何にも問題はありませんから、とりあえずやっ てみることをお勧めします。どうせ send-pr するまでは被害にあうのは自分 のマシンだけですから。

send-pr する

send-pr の pr は problem report の略で、ようするにバグ報告です。 FreeBSD にはバグ報告用の send-pr コマンドがあり、様々なバグの報告が可 能です。 ports の更新も problem report の一種と理解されています。

コマンドからも送ることができるのですが、筆者は web からの send-pr の方 をよく利用しています。 FreeBSD の(英語版) トップページから「バグ報告 (report a bug)」というページに行ってください。

あとは必要な要件を埋めていきます。

Your Eletric Mail Address
メールアドレスを書きます
Your Name
自分の名前を書きます
Your Organization or Company
自分の所属する組織等を書きます。なくても可
One line summary of the problem
一行で簡単に報告の内容を書きます。ports の更新なら、 [update] ja-scim-skk to 0.4.0 などと書くことが多いです。
Category
カテゴリ。 ports の更新はすべて「ports」にしてください。
Class
maintainer-updateにします
Severity,Priority
変更する必要はありません。もっと深刻なバグの時にはいろいろと調整します。
Which FreeBSD Release You Are Using
使っている FreeBSD のバージョンです。 5.4-RELEASE であるとかそういうのが入ります。
Environment
uname -a した結果をそのまま貼り付けます。
Full Description
バグの詳細を書く欄なのですが、 ports の更新の場合は必要ないでしょう。私は update of ... のように1行サマリとおなじようなものを書いています。
How to repeat the problem
バグの場合に、再現する条件を書く欄なのですが ports の更新の場合は空欄で問題ありません。
Fix the problem if known
ここに自分で書いたパッチを貼り付けます

そうそう、最後の「パッチ」だけ作り方を説明しわすれていました。といって もこれは単純で、比較したい2つのディレクトリで diff -ru するだけです。

# cd /usr/ports/japanese
# diff -ru scim-skk{.orig,}

このコマンドの出力結果を、「Fix the problem if known」の欄に貼り付けま す。

で、所定の文字列(ロボット避け)を書いて Submit Problem Report ボタンを 押すと…… Problem Report が送られる、という仕組みです。このとき、自分 宛にメールが届くのできちんと確認しましょう。

これで終わり?

終わりです。

多少、作業が稚拙でも問題ではありません。 Problem Report はそのまま反映 されるわけではなく、専用の ports メンテナが内容をちゃんとチェックし、 おかしい方法であれば修正を施した上でコミットします。とはいえ、あまり ports メンテナの苦労のないようにきちんとしたものを送るべきですが……。

ともかく、変更がコミットされれば、「コミットしたよ!」というメールが届 きます(英語で)。そうなれば、全ての FreeBSD ユーザがあなたの変更の恩恵 にあずかることができます。

まれに「これってこういう問題が起きるんじゃないか?/何を意図してこれを やっているかわからないから教えてくれ」みたいなメールが来て議論する必要 に迫られることもあります。その場合は……まぁ、ひとまず英語を勉強してく ださい(とほほ)。たいていの場合、そんなことはありません。または ports-jp のメーリングリストに相談するという手もあるかもしれません。

この先には

興味が出てきたら、 ports のお勉強をすることをお勧めします。これには、 英語版の porter's handbook が良いでしょう(というかそれしかない)。日本語版もあるのですが、少々古い という問題が(今のところ)あって内容には最新の ports に合致しないものも あり、読むならば英語版がお勧めです。

また、細かい設定は /usr/ports/Mk/bsd.port.mk 等を見ると、どんな指定が 可能なのか、といったことがわかるでしょう。

また、もし新しい ports を自分で作ってみたいのであれば、よく似たものを 探してみるのが良いのではないかと思います。たとえば c/migemo の ports って今はないんですが、これ用の ports を作るなら、 migemo の ports が参 考になる可能性は高いです。などなど。

では、 Happy Hacking!

筆者について

筆者は一介の FreeBSD 愛好者です。 FreeBSD のメインストリームな人ではな く、 BUG に属することもなく、 users-jp を読むわけでもなく、淡々と使っ ています。いくつかの ports のメンテナでもあります。

変更履歴