FreeBSDのportsは18,000を越えるportがある。ヘッダとかを別のパッケージにしてしまうバイナリLinux distributionはパッケージ数が膨張する傾向があるので、これは十分すごい数だと思う。今回はportを自分で書いてしまおうというネタ。
いちおう、portを作る人のためのマニュアルがFreeBSD Porter’s Handbookとしてあるんだけど、いまいち最新の状況に追いついていない。ただ、ここで解説する内容はだいたいカバーしているので一読をお勧めする。
portsになくて、よさそうなソフトウェアがあったらportを書きましょう。portsにあるかないかは以下の手順で確認できる。
> cd /usr/ports
> make search name=FOO
もしくは、ports-mgmt/portsearchを使うという手もある。
> portsearch -n FOO
まずはport-mgmt/porttoolsをインストール。手作業でportを作るのはダメ、ぜったい。そして~/.porttoolsを作成。porttools(5)を参照のこと。
# FreeBSD Port Tools configuration file - see porttools(5)
# vim: ft=sh
EMAIL="cherry@trombik.org"
FULLNAME="Tomoyuki Sakurai"
BUILDROOT="/tmp"
ARCHIVE_DIR="/home/cherry/svk/ports/send-pr"
DIFF_VIEWER="more"
PORTLINT_FLAGS="abct"
で、作業ディレクトリを作成。
> mkdir ~/ports && cd ~/ports
> mkdir net && cd net
> port create nuff
> cd nuff
> ls
Makefile pkg-descr pkg-plist
Makefileの書式は独特で、shと同じ感覚で書くと痛い目にあう。
- 空白とタブは区別される
- 行末にバックスラッシュがあると、1行とみなされる
- 変数の代入には$はつかない(FOO=)、変数を使うときは${FOO}
- 変数には大文字が使われることが多い
# This is a comment
FOO= bar
# ${FOO}はbarに展開される
target-1:
${ECHO} "taget-1"
${ECHO} ${FOO}
# echo fooと同じ
${DO_THIS} && ${DO_THAT} \
&& ${THEN_DO_THIS_AGAIN}
HTMLだとタブが正確に反映されないことがあるので、このページからコピペする場合は要注意。
テンプレートのMakefileが作成されるので、これをベースに作業する。
# New ports collection makefile for: nuff
# Date created: 2008-06-01
# Whom: My Name <name@example.org>
#
# $FreeBSD$
#
PORTNAME= nuff
PORTVERSION=
#PORTREVISION= 0
#PORTEPOCH= 0
CATEGORIES=
MASTER_SITES=
#MASTER_SITE_SUBDIR=
#PKGNAMEPREFIX=
#PKGNAMESUFFIX=
#DISTNAME=
#EXTRACT_SUFX=
#DISTFILES=
#DIST_SUBDIR= ${PORTNAME}
#EXTRACT_ONLY=
MAINTAINER= name@example.org
COMMENT=
.include <bsd.port.pre.mk>
.include <bsd.port.post.mk>
必須の変数はコメントアウトされてて、.porttoolsに値の指定があるものはすでに代入されている。
まずは簡単なものから埋めていく。CATEGORIESにはそのパッケージのカテゴリを指定する。通常は/usr/ports直下のディレクトリ名。有効なカテゴリ名はbsd.port.mkのVALID_CATEGORIES。ここではnetにする。COMMENTは、そのパッケージの簡単な説明。READMEやWebサイトからパクってきてもいい。”Scheme-based low lovel networking framework”とでもしておく。MAINTAINERには自分の連絡先を。
次にファイルを取ってくるために必要な変数を埋めていく。これから定義する変数はファイルを取得するURLを形成する。PORTNAMEはそのportの名称。PORTVERSIONはソフトウェアのバージョンを入れる。MASTER_SITESには、ベースとなるURLを指定。例えば、以下の場合
PORTNAME= foo
PORTVERSION= 1.0
MASTER_SITES= http://example.org/download/
ファイルの取得に使われるURLは、”http://example.org/download/foo-1.0.tar.gz”になる。しかし、nuffのファイルの拡張子は.tgzなので拡張子も明示的に指定しなければダメ。拡張子はEXTRACT_SUFXで指定する。
PORTNAME= nuff
CATEGORIES= net
MASTER_SITES= http://hcsw.org/nuff/
EXTRACT_SUFX= .tgz
これでファイルの取得に必要な情報は揃ったので、実際にダウンロードしてみる。
# make fetch
=> nuff-1.2.1.tgz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch from http://hcsw.org/nuff/downloads/.
nuff-1.2.1.tgz 100% of 142 kB 87 kBps
defaultでファイルは/usr/ports/distfilesに保存されるので、そのディレクトリに対する書き込み権限が必要。
ファイルのチェックサムを作成して確認。
> make makesum
> cat distinfo
MD5 (nuff-1.2.1.tgz) = 9819654000a117fe5132e0472659828e
SHA256 (nuff-1.2.1.tgz) = a8196ab094401b7ccdb31ad29ae41fd80a7fab100a3f7aa04c01704c70742f3c
SIZE (nuff-1.2.1.tgz) = 145502
次に、そのファイルを展開する。tgzやtar.gzの場合は自動的に展開される。
> make extract
===> Extracting for nuff-1.2.1
=> MD5 Checksum OK for nuff-1.2.1.tgz.
=> SHA256 Checksum OK for nuff-1.2.1.tgz.
もし、tbzやzipだった場合は、USE_BZIP2やUSE_ZIPをyesにしておくと、適切なコマンドが選択され、必要なら依存関係(zipはbase systemにないから)も自動で追加してくれる。カレントディレクトリ直下のworkにファイルは展開される。
> cd work/nuff
さて、ここから実際のbuildに入る。ファイルはworkディレクトリにあるので、READMEやINSTALLなどの文書を読んで、必要な依存関係やbuildオプションを調べる。多くの場合、configureスクリプトによって、build前に必要な要件(必要なコマンドやライブラリがインストールされているか)を満たしているかを確認したり、環境依存の変数を定義する。しかし、READMEを読むとnuffはconfigureを使わないらしい。また、buildにはGNU makeを使うらしい。FreeBSDのmake(1)はいわゆるBSD makeなので、明示的にgmakeを使わないとダメということ。また、Makefileのファイル名も”GNUmakefile”という一般的ではないファイル名になってる。つまり、gmakeに-fオプションでMakefileを指定してやらないといけない。冒頭でいくつかの変数が定義されているので、これを必要に応じて定義してやればいいらしい。依存関係としては、libpcapとlibdnetの2つ。libpcapはFreeBSDのbase systemに含まれているのでインストールの必要はない。libdnetはnet/libdnetとしてportsに含まれているので、あらかじめインストールしておく。gmakeがまだインストールされていなければdevel/gmakeを入れておく。
############################################################
######## Main build system for the nuff kernel
######## Requires GNU Make
############################################################
# Configuring the nuff kernel is a 3 step process:
# (1) Choose a main nuff install location
export NUFFDIR=/usr/local/nuffcode
# (2) Choose a build type:
export OPTIONS=-DBLOCKING_PCAP_NEXT # Linux
#export OPTIONS=-DUSE_BIOCIMMEDIATE -DUSE_PCAP_LOCK # OpenBSD
# (3) Specify include and linker paths for libpcap and libdnet
## You can either use a directory with the libraries in it:
export NUFFLIBDIR=/home/doug/nuff
必要なのは、インストール先のディレクトリ(NUFFDIR)、各種オプション(OPTIONS)、必要なライブラリとヘッダファイルのパス(*_INCDIRと*_LNKDIR)。libdnetのファイルがどこにインストールされたかはpkg_info -L libdnet-$VERSIONでわかる。それによると、ライブラリは/usr/local/libに、ヘッダは/usr/local/includeにある。libpcapはbase systemにあるので、それぞれ/usr/libと/usr/includeにある。このファイルを書き換える(patchを当てる)という方法もあるけれど、makeにはコマンドラインで変数を定義できるので、そっちの方が簡単。
> gmake -f GNUmakefile PCAP_INCDIR=/usr/include PCAP_LNKDIR=/usr/lib \
DNET_INCDIR=/usr/local/include DNET_LNKDIR=/usr/local/lib
cd src ; gmake
gmake[1]: Entering directory `/usr/home/cherry/svk/ports/net/nuff/work/nuff/src'
...
とりあえずコンパイルは通った。実行ファイルnuffがカレントディレクトリにできている。簡単なテストをしてみる。
> ./nuff resolve -- example.org
example.org 208.77.188.166
lddで動的にロードされるライブラリを確認する。もしかすると、要件として書かれていない依存関係がこれで見つかるかもしれない。
> ldd nuff
nuff:
libm.so.4 => /lib/libm.so.4 (0x2808e000)
libpcap.so.4 => /lib/libpcap.so.4 (0x280a4000)
libdnet.so => /usr/local/lib/libdnet.so (0x280c9000)
libc.so.6 => /lib/libc.so.6 (0x280d4000)
libmとlibcはbaseに含まれるライブラリなので無問題。/usr/localで始まるライブラリはlibdnetだけ、ということで、依存関係もOK。
次はインストールなんだけど、用意されているMakefileに任せるか、自分でインストールするかを決めなければいけない。install:で始まるinstall targetを見ると、NUFFDIRで指定されたディレクトリにインストールしてくれるらしい。しかし、ここでは自分でインストールする(portsのdo-install targetを自分で書く)ことにする。./configureとかを使わないで書かれている場合、FreeBSDのポリシーに従ってインストールできない、もしくは困難だから。ということで、portのMakefileを編集していく。
> cd ../../
> vim Makefile
ようは、makeにはgmakeを使って、gmakeに適切な引数を与えてやればいい。そのための変数がbsd.port.mkにすでに定義されているので、それを使う。
USE_GMAKE= yes
MAKE_ARGS= PCAP_INCDIR=/usr/include PCAP_LNKDIR=/usr/lib \
DNET_INCDIR=${LOCALBASE}/include DNET_LNKDIR=${LOCALBASE}/lib
USE_GMAKEで、「makeにはgmakeを使います」と宣言。これで自動的にdevel/gmakeに対する適切な依存関係も指定してくれる。MAKE_ARGSはそのgmakeに渡す引数。ほとんどの場合、パスは変数を使って指定する。defaultで${LOCALBASE}は/usr/localに展開される。似たような変数にPREFIXがある。これもdefaultでは/usr/localなのだけど、注意深く使い分ける必要がある。
PREFIXはそのパッケージが実際にインストールされるベースのディレクトリ。LOCALBASEは一般的にportsによってインストールされるベースのディレクトリ。この違いはporttoolsを使っているとわかりやすい。porttoolsのport testでは、一時ディレクトリを作成してそこにインストールする。そのディレクトリが/tmp/fooだと仮定すると、PREFIXは/tmp/foo、LOCALBASEは/usr/localになる。ここでgmakeに渡す引数は、インストールされているライブラリとヘッダのパスなので、MAKE_ARGSでPREFIXを使うと、DNET_INCDIRは/tmp/foo/includeになってしまう。当然、一時ディレクトリにlibdnetはインストールされていないので、コンパイラは必要なファイルを見つけられない。なので、ここで使うのはLOCALBASEでなくてはいけない。なんでこんなことになっているかというと、portsは/usr/local以外のディレクトリにもインストールできるようにしているから(例えば、diskless clientのためにNFSでexportするとか)。これはよく間違いやすいので、注意しましょう(porttoolsを使っていれば、こうしたbugはだいたい見つけられる)。
これでbuildはできるはず。
> port test
===> Validating port with portlint
WARN: Makefile: only one MASTER_SITE configured. Consider adding additional mirrors.
0 fatal errors and 1 warning found.
===> flags: PREFIX=/tmp/nuff-1.2.1 NO_DEPENDS=yes PKG_DBDIR=/tmp/pkg_db.AsuvZDmw
===> Cleaning workspace before port test
===> Cleaning for nuff-1.2.1
===> Extracting for nuff-1.2.1
=> MD5 Checksum OK for nuff-1.2.1.tgz.
=> SHA256 Checksum OK for nuff-1.2.1.tgz.
===> Patching for nuff-1.2.1
===> Configuring for nuff-1.2.1
===> Building for nuff-1.2.1
cd: can't cd to /usr/home/cherry/svk/ports/net/nuff/work/nuff-1.2.1
*** Error code 2
おっと、エラーが出てます。cdできないと言っているので確認してみると、展開したディレクトリ名(nuff)がportsの期待するディレクトリ名(nuff-1.2.1)と異なっているのが原因。
> ls work
nuff
このパスはWRKSRCとしてbsd.port.mkで定義されている。defaultは${WRKDIR}/${DISTNAME}。これを上書きしてしまえばよい。
WRKSRC= ${WRKDIR}/${PORTNAME}
この例のように、とにかく変数を使うこと。hard-codeしてしまうとアップデートのときや修正のときに書き換える場所が増えてしまう。
再度挑戦。
> make clean && make
===> Cleaning for nuff-1.2.1
===> Extracting for nuff-1.2.1
=> MD5 Checksum OK for nuff-1.2.1.tgz.
=> SHA256 Checksum OK for nuff-1.2.1.tgz.
===> Patching for nuff-1.2.1
===> nuff-1.2.1 depends on executable: gmake - found
===> Configuring for nuff-1.2.1
===> Building for nuff-1.2.1
gmake: Makefile: No such file or directory
gmake: *** No rule to make target `Makefile'. Stop.
*** Error code 2
まだダメ。Makefileが見つからないと言ってる。そうそう、MakefileではなくてGNUmakefileだったっけ。実行するMakfileのファイル名はMAKEFILEで定義されている。defaultは当然Makefile。これも上書きする。
MAKEFILE= GNUmakefile
3度目の正直。
> make clean && make
===> Cleaning for nuff-1.2.1
===> Extracting for nuff-1.2.1
...
mv src/nuff .
はい、makeが通りました。次に、do-install targetをGNUmakefileを参考にしながら自分で書く。よーするに、いくつかのディレクトリを作成して、ファイルをそこにコピーしているだけ(なぜかnuffバイナリはコピーされてない)。が、このインストールにも注意が必要。どこに何をインストールするかがそのdistributionのポリシーと大きく関わってくるから。まずはhier(7)を読んで、ディレクトリ構造とそれぞれの意味について理解する。/usr/local以下については書かれていないけれど、よく読むと/usr以下に準拠すると書いてある。なので、bin/sbin/etc/share/docs/examplesに何をインストールすればよいのか理解すること。ここで関わってるのは、shareとdocs。ffunとcodeは${PREFIX}/share/${PORTNAME}に、docs以下は${PREFIX}/docs/${PORTNAME}以下にインストールすればいい。このパスも、DATADIR、DOCSDIR変数として定義されている。で、インストールにはcp(1)を使ってはいけない。cpはファイルのパーミッションやuid/gidをそのままコピーしてしまうので、もしupstreamが適当なパーミッションやuid/gidを使っている場合、それがそのまま使われてしまう。なので、必ずinstall(1)を使うこと。で、このinstall(1)も変数が定義されている。バイナリ実行ファイルにはINSTALL_PROGRAM、スクリプトにはINSTALL_SCRIPT、通常のデータにはINSTALL_DATA、manにはINSTALL_MANなど。で、この変数を使ってインストールすればいい。
do-install:
${INSTALL_PROGRAM} ${WRKSRC}/nuff ${PREFIX}/bin/
これで実行ファイルはインストールできる。次に各種データファイルと文書。しかし、以下の例はうまく動作しない。*によるファイル名の展開が行われないのが原因。リテラルな${WRKSRC}/ffun/*がinstall(1)に渡されてしまう。
${INSTALL_DATA} ${WRKSRC}/ffun/* ${DATADIR}/
どうするかというと、make(1)のforを使う。
NUFF_SCM= compiler.scm describe.scm dispatcher.scm dns.scm
format.scm hashtables.scm init.scm layers.scm \
mapasync.scm nuff.scm nuffopen.scm queue.scm \
sched.scm tlists.scm unixopts.scm
do-install:
.for F in ${NUFF_SCM}
${INSTALL_DATA} ${WRKSRC}/ffun/${F} ${DATADIR}/
.endfor
しかし、もっと便利な変数がbsd.port.mkにはある。それがCOPYTREE_*。これを使えば、あるディレクトリ以下をまとめてインストールできる。注意すべきなのは、COPYTREE_*が呼ばれるカレントディレクトリによって、インストール先のディレクトリ名も変わること。また、Makefileの中では、カレントディレクトリを変更できるのは、1つのコマンドでのみ。そのコマンドの実行後にはもとのディレクトリに戻る。なので、1つのshellでディレクトリの移動とコマンドの実行を行う必要がある。つまり、(cd ${DIR} && command …)とする必要がある。
do-install:
${INSTALL_PROGRAM} ${WRKSRC}/nuff ${PREFIX}/bin/
( cd ${WRKSRC} && ${COPYTREE_SHARE} ffun ${DATADIR}/ )
( cd ${WRKSRC} && ${COPYTREE_SHARE} code ${DATADIR}/ )
( cd ${WRKSRC}/docs && ${COPYTREE_SHARE} . ${DOCSDIR}/ )
> port test
===> Validating port with portlint
WARN: Makefile: only one MASTER_SITE configured. Consider adding additional mirrors.
0 fatal errors and 1 warning found.
===> flags: PREFIX=/tmp/nuff-1.2.1 NO_DEPENDS=yes PKG_DBDIR=/tmp/pkg_db.0TzmDUrq
===> Cleaning workspace before port test
===> Cleaning for nuff-1.2.1
...
===> Checking pkg_info
nuff-1.2.1 Scheme-based low lovel networking framework
===> Checking shared library dependencies
===> Deinstalling for net/nuff
===> Deinstalling nuff-1.2.1
===> Extra files and directories check
bin/nuff
share/doc/nuff/C_API
share/doc/nuff/LICENSE
share/doc/nuff/TS_BUILDING
...
“Extra files and directories check”以下の出力が一時ディレクトリにインストールされたファイル名。これをそのままpkg-plist(インストールされるファイルの一覧)に書く。
> head pkg-plist
@comment $FreeBSD$
bin/nuff
share/doc/nuff/C_API
share/doc/nuff/LICENSE
share/doc/nuff/TS_BUILDING
share/doc/nuff/TS_CHANGES
share/doc/nuff/TS_COPYING
share/doc/nuff/TS_HACKING
share/doc/nuff/TS_MANUAL
share/doc/nuff/TS_TRIBUTE
これでうまくいくはずなのだけど、port testの前にportlintを実行してみる。
> portlint -abt
WARN: /usr/home/cherry/svk/ports/net/nuff/pkg-plist: [3]: If and only if your port is DOCSDIR-safe (that is, a user can override DOCSDIR when building this port and the port will still work correctly) consider using DOCSDIR macro; if you are unsure if this this port is DOCSDIR-safe, then ignore this warning
なんか大量に警告が出てます。ようするに、pkg-plistでも変数使え、ということ。Makefileの中で${FOO}として使えた変数は、%%FOO%%になる。これをさっそく修正。vimなら以下のコマンドで一発置換できる。
:%s#share/doc/nuff#%%DOCSDIR%%#
:%s#share/nuff#%%DATADIR%%#
再度挑戦。
> portlint -abt
WARN: /usr/home/cherry/svk/ports/net/nuff/pkg-plist: Both ``%%PORTDOCS%%@dirrm %%DOCSDIR%%'' and ``%%PORTDOCS%%@unexec %D/%%DOCSDIR%% 2>/dev/null || true'' are missing. At least one should be used.
WARN: Makefile: use ".if !defined(NOPORTDOCS)" to wrap installation of files into /usr/local/share/doc.
WARN: Makefile: only one MASTER_SITE configured. Consider adding additional mirrors.
0 fatal errors and 3 warnings found.
まだ文句言われています。1番目はDOCSDIRの適切な削除方法、2番目はNOPORTDOCSが定義されているときは関連文書をインストールしないようにしなさい、3番目はファイルの配布サイトが1つしか指定されてない、という警告。最後はともかく、2つは修正しましょう。
まずは%%DOCSDIR%%で始まる行を%%PORTDOCS%%%%DOCSDIR%%に置換。vimなら以下のコマンド。
:%s#^%%DOCSDIR%%/#%%PORTDOCS%%%%DOCSDIR%%/#
同様にdirrmにも%%PORTDOCS%%を追加。
%%PORTDOCS%%@dirrm %%DOCSDIR%%
で、Makefileの文書のインストール箇所に条件を指定。
.if !defined(NOPORTDOCS)
( cd ${WRKSRC}/docs && ${COPYTREE_SHARE} . ${DOCSDIR}/ )
.endif
これで、ユーザがNOPORTDOCS=yesしている場合は、文書はインストールされない。なぜこういうオプションがあるかというと、組み込みなどのディスクスペースに余裕がない場合は、実行に不要なファイルはインストールしない、という選択肢をユーザに与えるため。
> port test
===> Validating port with portlint
WARN: Makefile: only one MASTER_SITE configured. Consider adding additional mirrors.
0 fatal errors and 1 warning found.
...
===> Checking pkg_info
nuff-1.2.1 Scheme-based low lovel networking framework
===> Checking shared library dependencies
/lib/libc.so.6
/lib/libm.so.4
/lib/libpcap.so.4
/usr/local/lib/libdnet.so
===> Deinstalling for net/nuff
===> Deinstalling nuff-1.2.1
===> Extra files and directories check
===> Cleaning up after port test
===> Cleaning for nuff-1.2.1
===> Removing existing /tmp/nuff-1.2.1 dir
===> Done.
“Checking shared library dependencies”でlddの結果も出ている(ここではすでに確認したけど)。余分なファイルが残っていなかったら、これでOK、ではなくて、依存関係がまだ足りない。port testでは依存関係のテストが省かれているので、自分で依存関係の指定と確認をする必要がある。
依存関係にはいくつかあるけれど、多用するのはBUILD_DEPENDS(コンパイル時に依存)、RUN_DEPENDS(実行時に依存)、LIB_DEPENDS(ライブラリの依存関係)。ここで依存しているのはlibdnet。書式は”$NAME:$DIRECTORY”。$NAMEにはPOSIXの正規表現が使える。以下をCOMMENTの後ろに追加。
LIB_DEPENDS= dnet:${PORTSDIR}/net/libdnet
正確にはgmakeにもBUILD_DEPENDしているけれど、これはUSE_GMAKEがよきに計らってくれる。実際に依存関係でlibdnetがインストールされるかを確認。
# pkg_deinstall -f libnet-1.11_1
...
# make
実際にインストール。
# make install package clean
正常にインストールできれば成功。で、実際に実行できるのかテスト。
> nuff
FATAL: Unable to locate NUFFDIR
おーっと。コンパイル時にNUFFDIRを定義しておかないといけないんだった。インストールしたのは${DATADIR}だから、これをMAKE_ARGSに追加すればいい。
MAKE_ARGS= PCAP_INCDIR=/usr/include PCAP_LNKDIR=/usr/lib \
DNET_INCDIR=${LOCALBASE}/include DNET_LNKDIR=${LOCALBASE}/lib \
NUFFDIR=${DATADIR}
もう一度インストールし直して、実行。
# make deinstall && make clean && make install
...
> nuff
nuff - the Network Universal Frame Forge - by Doug Hoyte
[nuff kernel v1.2.1] [nuffdir /usr/local/share/nuff]
^D
> nuff resolve -- example.org
example.org 208.77.188.166
成功。
おっと、まだpkg-descrが空っぽだ。pkg-descrはそのportの簡単な説明。COMMENTより長くてもいい。72行程度で改行すること。vimならVで範囲指定して!fmt -w 72。WWWにはサイトのURLを。
> cat pkg-descr
Nuff is the Network Universal Frame Forge. Nuff bundles together a
scheme interpreter, low-level bindings to unix networking interfaces,
and powerful scheme functions and macros for dealing with network
packets.
WWW: http://hcsw.org/nuff/
最後にMakefileのコメントを削除する。最終的なMakefileはこうなる。
# New ports collection makefile for: nuff
# Date created: 2008-06-01
# Whom: Tomoyuki Sakurai <cherry@trombik.org>
#
# $FreeBSD$
#
PORTNAME= nuff
PORTVERSION= 1.2.1
CATEGORIES= net
MASTER_SITES= http://hcsw.org/nuff/downloads/
EXTRACT_SUFX= .tgz
MAINTAINER= cherry@trombik.org
COMMENT= Scheme-based low lovel networking framework
LIB_DEPENDS= dnet:${PORTSDIR}/net/libdnet
USE_GMAKE= yes
MAKE_ARGS= PCAP_INCDIR=/usr/include PCAP_LNKDIR=/usr/lib \
DNET_INCDIR=${LOCALBASE}/include DNET_LNKDIR=${LOCALBASE}/lib \
NUFFDIR=${DATADIR}
WRKSRC= ${WRKDIR}/${PORTNAME}
MAKEFILE= GNUmakefile
do-install:
${INSTALL_PROGRAM} ${WRKSRC}/nuff ${PREFIX}/bin/
( cd ${WRKSRC} && ${COPYTREE_SHARE} ffun ${DATADIR}/ )
( cd ${WRKSRC} && ${COPYTREE_SHARE} code ${DATADIR}/ )
.if !defined(NOPORTDOCS)
( cd ${WRKSRC}/docs && ${COPYTREE_SHARE} . ${DOCSDIR}/ )
.endif
.include <bsd.port.pre.mk>
.include <bsd.port.post.mk>
ここまでできたらsend-pr(1)。といっても、porttoolsにはsubmitというサブコマンドがあって、そいつがtemplateまで作ってくれる。新しいportをsubmitするなら、ほとんどすることはないといってもいい(既存のportに対するpatchの場合は、問題点を説明したり、適切なSynopsis:を書く必要がある)。Description:はpkg-descrからコピーしてくれるし、shar(1)ファイルも自動的に生成してくれる。
> port submit
エディタを終了すれば、PRが送信される。あとは、GNUTS(FreeBSDで使われているbug tracking system)からの連絡を待つのみ。そのうちcommiterが不具合の指摘やcommitをしてくれる。commitされたら、あなたがmaintainerです。upstreamのリリースやbug reportに目を通して、アップデートやpatchの適用をします。
最後に、これでOKかというとまだ改善点はある。CFLAGSが反映されていないとか、インストール後にユーザになんらかのメッセージを表示するなど。このportはsimpleだったけど、それでもそれなりに手がかかります。慣れればどうってことないんですが、それでもややこしいパッケージはいろいろある。それから、bsd.port.mkをはじめとする/usr/ports/Mk以下のMakefileがマニュアルみたいなものなので、これを読んで勉強しましょう。ということで、がんばってsend-prしてみてください。そうすれば、使ってくれた人がbugを報告してくれるかもしれないし、portを書いた人がいなくなっても誰かが面倒見てくれる*かも*しれない。send-prしないにしても、site localなパッケージをportにしておくことには意味がある。どのようにbuildしたのか文書化できるし、VMSにつっこめば履歴も管理できる。そして、puppetで管理することもできる、といいことたくさん。野良buildは20世紀のバッドノウハウです。
Happy porting!